Wed Jul 24 13:12:34 2019 UTC ()
Add support for device tree.
+ CCM (clk)
+ COM (uart)
+ GPIO
+ IOMUX (pin control)
+ PCIe
+ SDHC
+ USB Host
+ USB phy
(hkenken)
diff -r0 -r1.1 src/sys/arch/arm/imx/imx6_gpcreg.h
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/files.imx6
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/if_enet_imx.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_ahcisata.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_clk.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_com.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_gpc.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_gpio.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_iomux.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_pcie.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_platform.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_platform.h
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_sdhc.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_usb.c
diff -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_usbphy.c
diff -r0 -r1.1 src/sys/arch/evbarm/conf/IMX
diff -r0 -r1.1 src/sys/arch/evbarm/conf/files.imx
diff -r0 -r1.1 src/sys/arch/evbarm/conf/mk.imx
diff -r0 -r1.1 src/sys/arch/evbarm/conf/std.imx
/* $NetBSD: imx6_gpcreg.h,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _ARM_IMX_IMX6_GPCREG_H_
#define _ARM_IMX_IMX6_GPCREG_H_
#define GPC_CNTR 0x00000000
#define GPC_PGR 0x00000004
#define GPC_IMR1 0x00000008
#define GPC_IMR2 0x0000000C
#define GPC_IMR3 0x00000010
#define GPC_IMR4 0x00000014
#define GPC_ISR1 0x00000018
#define GPC_ISR2 0x0000001C
#define GPC_ISR3 0x00000020
#define GPC_ISR4 0x00000024
#endif /* _ARM_IMX_IMX6_GPCREG_H_ */
# $NetBSD: files.imx6,v 1.1 2019/07/24 13:12:33 hkenken Exp $
#
# Configuration info for the Freescale i.MX6
#
file arch/arm/arm32/arm32_boot.c
file arch/arm/arm32/arm32_kvminit.c
file arch/arm/arm32/arm32_reboot.c
file arch/arm/arm32/irq_dispatch.S
file arch/arm/arm32/armv7_generic_space.c
file arch/arm/arm/arm_generic_dma.c
file arch/arm/arm/bus_space_a4x.S
file arch/arm/imx/fdt/imx6_platform.c soc_imx
# SOC parameters
defflag opt_soc.h SOC_IMX
defflag opt_soc.h SOC_IMX6QDL: SOC_IMX
# Clock
device imxccm : clk
attach imxccm at fdt
file arch/arm/imx/imx6_ccm.c imxccm
file arch/arm/imx/fdt/imx6_clk.c imxccm
# GPC
device imxgpc
attach imxgpc at fdt
file arch/arm/imx/fdt/imx6_gpc.c imxgpc
# IOMUX
device imxiomux
attach imxiomux at fdt
file arch/arm/imx/fdt/imx6_iomux.c imxiomux
# GPIO controller
device imxgpio: gpiobus
attach imxgpio at fdt
file arch/arm/imx/imxgpio.c imxgpio
file arch/arm/imx/fdt/imx6_gpio.c imxgpio
# UART
device imxuart { } : bus_space_generic
attach imxuart at fdt with imx6_com
file arch/arm/imx/imxuart.c imxuart needs-flag
file arch/arm/imx/fdt/imx6_com.c imx6_com needs-flag
defflag opt_imxuart.h IMXUARTCONSOLE
# FEC
device enet: ether, ifnet, arp, mii, bus_dma_generic
attach enet at fdt
file arch/arm/imx/if_enet.c enet
file arch/arm/imx/fdt/if_enet_imx.c enet
# SATA
attach ahcisata at fdt with imx6_ahcisata
file arch/arm/imx/fdt/imx6_ahcisata.c imx6_ahcisata
# USB Controller
device imxusbc { [unit=-1], [irq=-1] } : bus_dma_generic
attach imxusbc at fdt with imxusbc_fdt
file arch/arm/imx/fdt/imx6_usb.c imxusbc_fdt
attach ehci at imxusbc with imxehci
file arch/arm/imx/imxusb.c imxehci
# USB PHY
device imxusbphy
attach imxusbphy at fdt
file arch/arm/imx/fdt/imx6_usbphy.c imxusbphy
# SDMMC
attach sdhc at fdt with imx6_sdhc
file arch/arm/imx/fdt/imx6_sdhc.c imx6_sdhc
# PCIe
device imxpcie: pcibus
attach imxpcie at fdt with imxpcie_fdt
file arch/arm/imx/imxpcie.c imxpcie
file arch/arm/imx/fdt/imx6_pcie.c imxpcie_fdt
/* $NetBSD: if_enet_imx.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_enet_imx.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/if_enetreg.h>
#include <arm/imx/if_enetvar.h>
#include <dev/fdt/fdtvar.h>
static const char * const compatible[] = {
"fsl,imx6q-fec",
NULL
};
static int enet_init_clocks(struct enet_softc *);
static void enet_phy_reset(const int);
int
enet_match(device_t parent, cfdata_t cf, void *aux)
{
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
void
enet_attach(device_t parent, device_t self, void *aux)
{
struct enet_softc *sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_space_tag_t bst = faa->faa_bst;
bus_space_handle_t bsh;
bus_addr_t addr;
bus_size_t size;
int error;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get enet registers\n");
return;
}
error = bus_space_map(bst, addr, size, 0, &bsh);
if (error) {
aprint_error(": couldn't map enet registers: %d\n", error);
return;
}
sc->sc_clk_enet = fdtbus_clock_get(phandle, "ahb");
if (sc->sc_clk_enet == NULL) {
aprint_error(": couldn't get clock ahb\n");
goto failure;
}
sc->sc_clk_enet_ref= fdtbus_clock_get(phandle, "ptp");
if (sc->sc_clk_enet_ref == NULL) {
aprint_error(": couldn't get clock ptp\n");
goto failure;
}
aprint_naive("\n");
aprint_normal(": Gigabit Ethernet Controller\n");
enet_phy_reset(phandle);
sc->sc_dev = self;
sc->sc_iot = bst;
sc->sc_ioh = bsh;
sc->sc_dmat = faa->faa_dmat;
sc->sc_imxtype = 6; /* i.MX6 */
sc->sc_rgmii = 1;
char intrstr[128];
if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
goto failure;
}
sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_NET, 0,
enet_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "failed to establish interrupt on %s\n",
intrstr);
goto failure;
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
enet_init_clocks(sc);
sc->sc_pllclock = clk_get_rate(sc->sc_clk_enet);
if (enet_attach_common(self) != 0)
goto failure;
return;
failure:
bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
return;
}
static int
enet_init_clocks(struct enet_softc *sc)
{
int error;
error = clk_enable(sc->sc_clk_enet);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable enet: %d\n", error);
return error;
}
error = clk_enable(sc->sc_clk_enet_ref);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable enet_ref: %d\n", error);
return error;
}
return 0;
}
static void
enet_phy_reset(const int phandle)
{
struct fdtbus_gpio_pin *reset;
int error;
reset = fdtbus_gpio_acquire(phandle, "phy-reset-gpios", GPIO_PIN_OUTPUT);
if (reset == NULL)
return;
u_int msec;
error = of_getprop_uint32(phandle, "phy-reset-duration", &msec);
if (error)
msec = 1;
/* Reset */
fdtbus_gpio_write(reset, 1);
delay(msec * 1000);
fdtbus_gpio_write(reset, 0);
fdtbus_gpio_release(reset);
}
/* $NetBSD: imx6_ahcisata.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_ahcisata.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <dev/ata/atavar.h>
#include <dev/ic/ahcisatavar.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_ahcisatareg.h>
#include <arm/imx/imx6_iomuxreg.h>
#include <arm/imx/imx6_ccmreg.h>
#include <arm/imx/imx6_ccmvar.h>
#include <dev/fdt/fdtvar.h>
static int imx6_ahcisata_match(device_t, cfdata_t, void *);
static void imx6_ahcisata_attach(device_t, device_t, void *);
struct imx6_ahcisata_softc {
struct ahci_softc sc;
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_space_handle_t sc_gpr_ioh;
void *sc_ih;
u_int sc_tx_level;
u_int sc_tx_boost;
u_int sc_tx_atten;
u_int sc_rx_eq;
u_int sc_ss;
struct clk *sc_clk_sata;
struct clk *sc_clk_sata_ref;
struct clk *sc_clk_ahb;
};
static int imx6_ahcisata_init(struct imx6_ahcisata_softc *);
static int imx6_ahcisata_phy_ctrl(struct imx6_ahcisata_softc *, uint32_t, int);
static int imx6_ahcisata_phy_addr(struct imx6_ahcisata_softc *, uint32_t);
static int imx6_ahcisata_phy_write(struct imx6_ahcisata_softc *, uint32_t, uint16_t);
static int imx6_ahcisata_phy_read(struct imx6_ahcisata_softc *, uint32_t);
static int imx6_ahcisata_init_clocks(struct imx6_ahcisata_softc *);
CFATTACH_DECL_NEW(imx6_ahcisata, sizeof(struct imx6_ahcisata_softc),
imx6_ahcisata_match, imx6_ahcisata_attach, NULL, NULL);
static int
imx6_ahcisata_match(device_t parent, cfdata_t cf, void *aux)
{
const char * const compatible[] = { "fsl,imx6q-ahci", NULL };
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imx6_ahcisata_attach(device_t parent, device_t self, void *aux)
{
struct imx6_ahcisata_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_addr_t ahci_addr;
bus_size_t ahci_size;
bus_addr_t addr;
bus_size_t size;
char intrstr[128];
int error;
if (fdtbus_get_reg(phandle, 0, &ahci_addr, &ahci_size) != 0) {
aprint_error(": couldn't get ahci registers\n");
return;
}
if (of_getprop_uint32(phandle, "fsl,transmit-level-mV", &sc->sc_tx_level) != 0)
sc->sc_tx_level = 1104;
if (of_getprop_uint32(phandle, "fsl,transmit-boost-mdB", &sc->sc_tx_boost) != 0)
sc->sc_tx_boost = 3330;
if (of_getprop_uint32(phandle, "fsl,transmit-atten-16ths", &sc->sc_tx_atten) != 0)
sc->sc_tx_atten = 9;
if (of_getprop_uint32(phandle, "fsl,receive-eq-mdB", &sc->sc_rx_eq) != 0)
sc->sc_rx_eq = 3000;
if (of_getprop_bool(phandle, "fsl,no-spread-spectrum") == false)
sc->sc_ss = 1;
sc->sc_clk_sata = fdtbus_clock_get(phandle, "sata");
if (sc->sc_clk_sata == NULL) {
aprint_error(": couldn't get clock sata\n");
return;
}
sc->sc_clk_sata_ref = fdtbus_clock_get(phandle, "sata_ref");
if (sc->sc_clk_sata_ref == NULL) {
aprint_error(": couldn't get clock sata_ref\n");
return;
}
sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
if (sc->sc_clk_ahb == NULL) {
aprint_error(": couldn't get clock ahb\n");
return;
}
aprint_naive("\n");
aprint_normal(": AHCI Controller\n");
aprint_debug_dev(self, "tx level %d [mV]\n", sc->sc_tx_level);
aprint_debug_dev(self, "tx boost %d [mdB]\n", sc->sc_tx_boost);
aprint_debug_dev(self, "tx atten %d [16ths]\n", sc->sc_tx_atten);
aprint_debug_dev(self, "rx eq %d [mdB]\n", sc->sc_rx_eq);
aprint_debug_dev(self, "ss %d\n", sc->sc_ss);
sc->sc_dev = self;
sc->sc.sc_atac.atac_dev = self;
sc->sc.sc_ahci_ports = 1;
sc->sc.sc_dmat = faa->faa_dmat;
sc->sc.sc_ahcit = faa->faa_bst;
sc->sc.sc_ahcis = ahci_size;
error = bus_space_map(sc->sc.sc_ahcit, ahci_addr, ahci_size, 0,
&sc->sc.sc_ahcih);
if (error) {
aprint_error(": couldn't map ahci registers: %d\n", error);
return;
}
sc->sc_iot = sc->sc.sc_ahcit;
sc->sc_ioh = sc->sc.sc_ahcih;
const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
aprint_error_dev(self, "Cannot map registers\n");
return;
}
if (imx6_ahcisata_init_clocks(sc) != 0) {
aprint_error_dev(self, "couldn't init clocks\n");
return;
}
if (imx6_ahcisata_init(sc) != 0) {
aprint_error_dev(self, "couldn't init ahci\n");
return;
}
if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
return;
}
sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_BIO, 0,
ahci_intr, &sc->sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "failed to establish interrupt on %s\n",
intrstr);
return;
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
ahci_attach(&sc->sc);
}
static int
imx6_ahcisata_phy_ctrl(struct imx6_ahcisata_softc *sc, uint32_t bitmask, int on)
{
uint32_t v;
int timeout;
v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR);
if (on)
v |= bitmask;
else
v &= ~bitmask;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, v);
for (timeout = 5000; timeout > 0; --timeout) {
v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
if (!!(v & SATA_P0PHYSR_CR_ACK) == !!on)
break;
delay(100);
}
if (timeout > 0)
return 0;
return -1;
}
static int
imx6_ahcisata_phy_addr(struct imx6_ahcisata_softc *sc, uint32_t addr)
{
delay(100);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, addr);
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 1) != 0)
return -1;
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 0) != 0)
return -1;
return 0;
}
static int
imx6_ahcisata_phy_write(struct imx6_ahcisata_softc *sc, uint32_t addr,
uint16_t data)
{
if (imx6_ahcisata_phy_addr(sc, addr) != 0)
return -1;
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, data);
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 1) != 0)
return -1;
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 0) != 0)
return -1;
if ((addr == SATA_PHY_CLOCK_RESET) && data) {
/* we can't check ACK after RESET */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
data | SATA_P0PHYCR_CR_WRITE);
return 0;
}
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 1) != 0)
return -1;
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 0) != 0)
return -1;
return 0;
}
static int
imx6_ahcisata_phy_read(struct imx6_ahcisata_softc *sc, uint32_t addr)
{
uint32_t v;
if (imx6_ahcisata_phy_addr(sc, addr) != 0)
return -1;
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 1) != 0)
return -1;
v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
if (imx6_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 0) != 0)
return -1;
return SATA_P0PHYSR_CR_DATA_OUT(v);
}
const static int tx_level[] = {
937,
947,
957,
966,
976,
986,
996,
1005,
1015,
1025,
1035,
1045,
1054,
1064,
1074,
1084,
1094,
1104,
1113,
1123,
1133,
1143,
1152,
1162,
1172,
1182,
1191,
1201,
1211,
1221,
1230,
1240,
};
const static int tx_boots[] = {
0,
370,
740,
1110,
1480,
1850,
2220,
2590,
2960,
3330,
3700,
4070,
4440,
4810,
5280,
5750,
};
const static int tx_atten[] = {
16,
14,
12,
10,
9,
8,
};
const static int rx_eq[] = {
500,
1000,
1500,
2000,
2500,
3000,
3500,
4000,
};
static int
imx6_ahcisata_search_regval(const int *values, int count, int val)
{
for (int i = 0; i < count; i++)
if (values[i] == val)
return i;
return -1;
}
static int
imx6_ahcisata_init(struct imx6_ahcisata_softc *sc)
{
uint32_t v;
int timeout;
int pllstat;
v = bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13);
/* clear */
v &= ~(IOMUX_GPR13_SATA_PHY_8 |
IOMUX_GPR13_SATA_PHY_7 |
IOMUX_GPR13_SATA_PHY_6 |
IOMUX_GPR13_SATA_SPEED |
IOMUX_GPR13_SATA_PHY_5 |
IOMUX_GPR13_SATA_PHY_4 |
IOMUX_GPR13_SATA_PHY_3 |
IOMUX_GPR13_SATA_PHY_2 |
IOMUX_GPR13_SATA_PHY_1 |
IOMUX_GPR13_SATA_PHY_0);
/* setting */
struct {
const int *array;
int count;
int val;
int def_val;
int mask;
} gpr13_sata_phy_settings[] = {
{ tx_level, __arraycount(tx_level), sc->sc_tx_level,
0x11, IOMUX_GPR13_SATA_PHY_2 },
{ tx_boots, __arraycount(tx_boots), sc->sc_tx_boost,
0x09, IOMUX_GPR13_SATA_PHY_3 },
{ tx_atten, __arraycount(tx_atten), sc->sc_tx_atten,
0x04, IOMUX_GPR13_SATA_PHY_4 },
{ rx_eq, __arraycount(rx_eq), sc->sc_rx_eq,
0x05, IOMUX_GPR13_SATA_PHY_8 }
};
for (int i = 0; i < __arraycount(gpr13_sata_phy_settings); i++) {
int val;
val = imx6_ahcisata_search_regval(
gpr13_sata_phy_settings[i].array,
gpr13_sata_phy_settings[i].count,
gpr13_sata_phy_settings[i].val);
if (val == -1)
val = gpr13_sata_phy_settings[i].def_val;
v |= __SHIFTIN(val, gpr13_sata_phy_settings[i].mask);
}
v |= __SHIFTIN(sc->sc_ss, IOMUX_GPR13_SATA_PHY_5);
v |= __SHIFTIN(0x12, IOMUX_GPR13_SATA_PHY_7); /* Rx SATA2m */
v |= __SHIFTIN(3, IOMUX_GPR13_SATA_PHY_6); /* Rx DPLL mode */
v |= __SHIFTIN(1, IOMUX_GPR13_SATA_SPEED); /* 3.0GHz */
v |= __SHIFTIN(1, IOMUX_GPR13_SATA_PHY_1); /* PLL clock enable */
bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13, v);
/* phy reset */
if (imx6_ahcisata_phy_write(sc, SATA_PHY_CLOCK_RESET,
SATA_PHY_CLOCK_RESET_RST) < 0) {
aprint_error_dev(sc->sc_dev, "cannot reset PHY\n");
return -1;
}
for (timeout = 50; timeout > 0; --timeout) {
delay(100);
pllstat = imx6_ahcisata_phy_read(sc, SATA_PHY_LANE0_OUT_STAT);
if (pllstat < 0) {
aprint_error_dev(sc->sc_dev,
"cannot read LANE0 status\n");
break;
}
if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE)
break;
}
if (timeout <= 0)
return -1;
/* Support Staggered Spin-up */
v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, v | SATA_CAP_SSS);
/* Ports Implmented. must set 1 */
v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_PI);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, v | SATA_PI_PI);
/* set 1ms-timer = AHB clock / 1000 */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS,
clk_get_rate(sc->sc_clk_ahb) / 1000);
return 0;
}
static int
imx6_ahcisata_init_clocks(struct imx6_ahcisata_softc *sc)
{
int error;
error = clk_enable(sc->sc_clk_sata);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error);
return error;
}
error = clk_enable(sc->sc_clk_sata_ref);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error);
return error;
}
error = clk_enable(sc->sc_clk_ahb);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error);
return error;
}
return 0;
}
/* $NetBSD: imx6_clk.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_clk.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/sysctl.h>
#include <sys/cpufreq.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/param.h>
#include <arm/imx/imx6_ccmvar.h>
#include <dev/clk/clk_backend.h>
#include <dev/fdt/fdtvar.h>
static struct clk *imx6_clk_decode(device_t, int, const void *, size_t);
static const struct fdtbus_clock_controller_func imx6_ccm_fdtclock_funcs = {
.decode = imx6_clk_decode
};
static struct clk *
imx6_clk_decode(device_t dev, int cc_phandle, const void *data, size_t len)
{
struct clk *clk;
/* #clock-cells should be 1 */
if (len != 4)
return NULL;
const u_int clock_id = be32dec(data);
clk = imx6_get_clock_by_id(clock_id);
if (clk)
return clk;
return NULL;
}
static void
imx6_clk_fixed_from_fdt(const char *name)
{
struct imx6_clk *iclk = (struct imx6_clk *)imx6_get_clock(name);
KASSERT(iclk != NULL);
char *path = kmem_asprintf("/clocks/%s", name);
int phandle = OF_finddevice(path);
kmem_free(path, strlen(path) + 1);
if (of_getprop_uint32(phandle, "clock-frequency", &iclk->clk.fixed.rate) != 0)
iclk->clk.fixed.rate = 0;
}
static int imxccm_match(device_t, cfdata_t, void *);
static void imxccm_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(imxccm, sizeof(struct imxccm_softc),
imxccm_match, imxccm_attach, NULL, NULL);
static int
imxccm_match(device_t parent, cfdata_t cfdata, void *aux)
{
const char * const compatible[] = { "fsl,imx6q-ccm", NULL };
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imxccm_attach(device_t parent, device_t self, void *aux)
{
struct imxccm_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
bus_addr_t addr;
bus_size_t size;
if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
return;
}
sc->sc_dev = self;
sc->sc_iot = faa->faa_bst;
if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
aprint_error(": can't map ccm registers\n");
return;
}
int phandle = OF_finddevice("/soc/aips-bus/anatop");
fdtbus_get_reg(phandle, 0, &addr, &size);
if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh_analog)) {
aprint_error(": can't map anatop registers\n");
return;
}
imxccm_attach_common(self);
imx6_clk_fixed_from_fdt("ckil");
imx6_clk_fixed_from_fdt("ckih");
imx6_clk_fixed_from_fdt("osc");
imx6_clk_fixed_from_fdt("anaclk1");
imx6_clk_fixed_from_fdt("anaclk2");
fdtbus_register_clock_controller(self, faa->faa_phandle,
&imx6_ccm_fdtclock_funcs);
}
/* $NetBSD: imx6_com.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_com.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include "opt_imxuart.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <dev/fdt/fdtvar.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imxuartreg.h>
#include <arm/imx/imxuartvar.h>
static int imx6_com_match(device_t, struct cfdata *, void *);
static void imx6_com_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(imx6_com, sizeof(struct imxuart_softc),
imx6_com_match, imx6_com_attach, NULL, NULL);
static const char * const compatible[] = {
"fsl,imx6q-uart",
NULL
};
static int
imx6_com_match(device_t parent, struct cfdata *cf, void *aux)
{
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imx6_com_attach(device_t parent, device_t self, void *aux)
{
struct imxuart_softc *sc = device_private(self);
struct imxuart_regs *regsp = &sc->sc_regs;
struct fdt_attach_args *faa = aux;
const int phandle = faa->faa_phandle;
bus_space_tag_t bst = faa->faa_bst;
bus_space_handle_t bsh;
char intrstr[128];
bus_addr_t addr;
bus_size_t size;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
return;
}
if (bus_space_map(bst, addr, size, 0, &bsh) != 0) {
aprint_error(": couldn't map registers\n");
return;
}
sc->sc_dev = self;
regsp->ur_iot = bst;
regsp->ur_iobase = addr;
regsp->ur_ioh = bsh;
if (imxuart_is_console(regsp->ur_iot, regsp->ur_iobase, ®sp->ur_ioh))
aprint_normal(" (console)");
aprint_normal("\n");
if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
return;
}
sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_SERIAL,
FDT_INTR_MPSAFE, imxuintr, sc);
if (sc->sc_ih == NULL)
aprint_error_dev(self, "failed to establish interrupt\n");
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
imxuart_attach_subr(sc);
}
/*
* Console support
*/
static int
imx6_com_console_match(int phandle)
{
return of_match_compatible(phandle, compatible);
}
static void
imx6_com_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
{
const int phandle = faa->faa_phandle;
bus_space_tag_t bst = faa->faa_bst;
bus_addr_t addr;
bus_size_t size;
tcflag_t flags;
int speed;
fdtbus_get_reg(phandle, 0, &addr, &size);
speed = fdtbus_get_stdout_speed();
if (speed < 0)
speed = 115200; /* default */
flags = fdtbus_get_stdout_flags();
imxuart_set_frequency(uart_freq, 2);
if (imxuart_cnattach(bst, addr, speed, flags) != 0)
panic("cannot attach console UART");
}
static const struct fdt_console imx6_com_console = {
.match = imx6_com_console_match,
.consinit = imx6_com_console_consinit,
};
FDT_CONSOLE(imx6_com, &imx6_com_console);
/* $NetBSD: imx6_gpc.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_gpc.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_gpcreg.h>
#include <arm/cortex/gic_intr.h>
#include <dev/fdt/fdtvar.h>
struct imxgpc_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
};
static int imxgpc_match(device_t, struct cfdata *, void *);
static void imxgpc_attach(device_t, device_t, void *);
static void *imxgpc_establish(device_t, u_int *, int, int,
int (*)(void *), void *);
static void imxgpc_disestablish(device_t, void *);
static bool imxgpc_intrstr(device_t, u_int *, char *, size_t);
struct fdtbus_interrupt_controller_func imxgpc_funcs = {
.establish = imxgpc_establish,
.disestablish = imxgpc_disestablish,
.intrstr = imxgpc_intrstr
};
CFATTACH_DECL_NEW(imxgpc, sizeof(struct imxgpc_softc),
imxgpc_match, imxgpc_attach, NULL, NULL);
static int
imxgpc_match(device_t parent, cfdata_t cf, void *aux)
{
const char * const compatible[] = { "fsl,imx6q-gpc", NULL };
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imxgpc_attach(device_t parent, device_t self, void *aux)
{
struct imxgpc_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_addr_t gpc_addr;
bus_size_t gpc_size;
int error;
if (fdtbus_get_reg(phandle, 0, &gpc_addr, &gpc_size) != 0) {
aprint_error(": couldn't get gpc registers\n");
return;
}
sc->sc_dev = self;
sc->sc_iot = faa->faa_bst;
error = bus_space_map(sc->sc_iot, gpc_addr, gpc_size, 0,
&sc->sc_ioh);
if (error) {
aprint_error(": couldn't map gpc registers: %d\n", error);
return;
}
error = fdtbus_register_interrupt_controller(self, faa->faa_phandle,
&imxgpc_funcs);
if (error) {
aprint_error(": couldn't register with fdtbus: %d\n", error);
return;
}
aprint_naive("\n");
aprint_normal(": General Power Controller\n");
return;
}
static void *
imxgpc_establish(device_t dev, u_int *specifier, int ipl, int flags,
int (*func)(void *), void *arg)
{
/* 1st cell is the interrupt type; 0 is SPI, 1 is PPI */
/* 2nd cell is the interrupt number */
/* 3rd cell is flags */
const u_int type = be32toh(specifier[0]);
const u_int intr = be32toh(specifier[1]);
const u_int irq = type == 0 ? IRQ_SPI(intr) : IRQ_PPI(intr);
const u_int trig = be32toh(specifier[2]) & 0xf;
const u_int level = (trig & 0x3) ? IST_EDGE : IST_LEVEL;
const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
aprint_debug_dev(dev, "intr establish irq %d, level %d\n", irq, level);
return intr_establish(irq, ipl, level | mpsafe, func, arg);
}
static void
imxgpc_disestablish(device_t dev, void *ih)
{
intr_disestablish(ih);
}
static bool
imxgpc_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
{
/* 1st cell is the interrupt type; 0 is SPI, 1 is PPI */
/* 2nd cell is the interrupt number */
/* 3rd cell is flags */
if (!specifier)
return false;
const u_int type = be32toh(specifier[0]);
const u_int intr = be32toh(specifier[1]);
const u_int irq = type == 0 ? IRQ_SPI(intr) : IRQ_PPI(intr);
snprintf(buf, buflen, "irq %d", irq);
return true;
}
/* $NetBSD: imx6_gpio.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_gpio.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include "gpio.h"
#define _INTR_PRIVATE
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/gpio.h>
#include <dev/gpio/gpiovar.h>
#include <arm/pic/picvar.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imxgpioreg.h>
#include <arm/imx/imxgpiovar.h>
#include <dev/fdt/fdtvar.h>
static void *imx6_gpio_fdt_acquire(device_t, const void *, size_t, int);
static void imx6_gpio_fdt_release(device_t, void *);
static int imx6_gpio_fdt_read(device_t, void *, bool);
static void imx6_gpio_fdt_write(device_t, void *, int, bool);
static void *imxgpio_establish(device_t, u_int *, int, int,
int (*)(void *), void *);
static void imxgpio_disestablish(device_t, void *);
static bool imxgpio_intrstr(device_t, u_int *, char *, size_t);
static struct fdtbus_interrupt_controller_func imxgpio_funcs = {
.establish = imxgpio_establish,
.disestablish = imxgpio_disestablish,
.intrstr = imxgpio_intrstr
};
static struct fdtbus_gpio_controller_func imx6_gpio_funcs = {
.acquire = imx6_gpio_fdt_acquire,
.release = imx6_gpio_fdt_release,
.read = imx6_gpio_fdt_read,
.write = imx6_gpio_fdt_write
};
const int imxgpio_ngroups = GPIO_NGROUPS;
int
imxgpio_match(device_t parent, cfdata_t cf, void *aux)
{
const char * const compatible[] = {
"fsl,imx6q-gpio",
NULL
};
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
void
imxgpio_attach(device_t parent, device_t self, void *aux)
{
struct imxgpio_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
char intrstr[128];
const int phandle = faa->faa_phandle;
bus_space_handle_t ioh;
bus_addr_t addr;
bus_size_t size;
int error;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
return;
}
error = bus_space_map(faa->faa_bst, addr, size, 0, &ioh);
if (error) {
aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
return;
}
aprint_naive("\n");
aprint_normal(": GPIO (%s)\n", fdtbus_get_string(phandle, "name"));
sc->gpio_memt = faa->faa_bst;
sc->gpio_memh = ioh;
sc->gpio_unit = (addr - IMX6_AIPS1_BASE - AIPS1_GPIO1_BASE) / 0x4000;
sc->gpio_irqbase = PIC_MAXSOURCES + sc->gpio_unit * GPIO_NPINS;
if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
return;
}
sc->gpio_is = fdtbus_intr_establish(phandle, 0, IPL_HIGH, 0,
pic_handle_intr, &sc->gpio_pic);
if (sc->gpio_is == NULL) {
aprint_error_dev(self, "couldn't establish interrupt on %s\n",
intrstr);
return;
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
if (!fdtbus_intr_str(phandle, 1, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
return;
}
sc->gpio_is_high = fdtbus_intr_establish(phandle, 1, IPL_HIGH, 0,
pic_handle_intr, &sc->gpio_pic);
if (sc->gpio_is_high == NULL) {
aprint_error_dev(self, "couldn't establish interrupt on %s\n",
intrstr);
return;
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
fdtbus_register_gpio_controller(self, phandle, &imx6_gpio_funcs);
error = fdtbus_register_interrupt_controller(self, phandle,
&imxgpio_funcs);
if (error) {
aprint_error(": couldn't register with fdtbus: %d\n", error);
return;
}
imxgpio_attach_common(self);
}
static void *
imx6_gpio_fdt_acquire(device_t dev, const void *data, size_t len, int flags)
{
struct imxgpio_softc * const sc = device_private(dev);
struct imxgpio_pin *gpin;
const u_int *gpio = data;
if (len != 12)
return NULL;
const u_int pin = be32toh(gpio[1]);
const bool actlo = be32toh(gpio[2]) & 1;
gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP);
gpin->pin_no = pin;
gpin->pin_flags = flags;
gpin->pin_actlo = actlo;
imxgpio_pin_ctl(sc, gpin->pin_no, gpin->pin_flags);
return gpin;
}
static void
imx6_gpio_fdt_release(device_t dev, void *priv)
{
struct imxgpio_softc * const sc = device_private(dev);
struct imxgpio_pin *gpin = priv;
imxgpio_pin_ctl(sc, gpin->pin_no, GPIO_PIN_INPUT);
kmem_free(gpin, sizeof(*gpin));
}
static int
imx6_gpio_fdt_read(device_t dev, void *priv, bool raw)
{
struct imxgpio_softc * const sc = device_private(dev);
struct imxgpio_pin *gpin = priv;
int val;
val = imxgpio_pin_read(sc, gpin->pin_no);
if (!raw && gpin->pin_actlo)
val = !val;
return val;
}
static void
imx6_gpio_fdt_write(device_t dev, void *priv, int val, bool raw)
{
struct imxgpio_softc * const sc = device_private(dev);
struct imxgpio_pin *gpin = priv;
if (!raw && gpin->pin_actlo)
val = !val;
imxgpio_pin_write(sc, gpin->pin_no, val);
}
static void *
imxgpio_establish(device_t dev, u_int *specifier, int ipl, int flags,
int (*func)(void *), void *arg)
{
struct imxgpio_softc * const sc = device_private(dev);
/* 1st cell is the interrupt number */
/* 2nd cell is flags */
const u_int intr = be32toh(specifier[0]);
const u_int trig = be32toh(specifier[1]) & 0xf;
u_int level;
if ((trig & 0x1) && (trig & 0x2))
level = IST_EDGE_BOTH;
else if (trig & 0x1)
level = IST_EDGE_RISING;
else if (trig & 0x2)
level = IST_EDGE_FALLING;
else if (trig & 0x4)
level = IST_LEVEL_HIGH;
else
level = IST_LEVEL_LOW;
const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
aprint_debug_dev(dev, "intr establish irq %d, level %d\n",
sc->gpio_irqbase + intr, level);
return intr_establish(sc->gpio_irqbase + intr, ipl, level | mpsafe, func, arg);
}
static void
imxgpio_disestablish(device_t dev, void *ih)
{
intr_disestablish(ih);
}
static bool
imxgpio_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
{
struct imxgpio_softc * const sc = device_private(dev);
/* 1st cell is the interrupt number */
/* 2nd cell is flags */
if (!specifier)
return false;
const u_int intr = be32toh(specifier[0]);
snprintf(buf, buflen, "irq %d (gpio%d %d)",
sc->gpio_irqbase + intr, sc->gpio_unit, intr);
return true;
}
/* $NetBSD: imx6_iomux.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_iomux.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_iomuxreg.h>
#include <dev/fdt/fdtvar.h>
struct imxiomux_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
int sc_phandle;
};
#define CONFIG_NO_PAD_CTL __BIT(31)
#define CONFIG_SION __BIT(30)
static int
imx6_pinctrl_set_config(device_t dev, const void *data, size_t len)
{
struct imxiomux_softc * const sc = device_private(dev);
int pins_len;
uint32_t reg;
if (len != 4)
return -1;
const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
const u_int *pins = fdtbus_get_prop(phandle, "fsl,pins", &pins_len);
aprint_debug_dev(sc->sc_dev, "name %s\n", fdtbus_get_string(phandle, "name"));
while (pins_len >= 24) {
u_int mux_reg = be32toh(pins[0]);
u_int conf_reg = be32toh(pins[1]);
u_int input_reg = be32toh(pins[2]);
u_int mux_mode = be32toh(pins[3]);
u_int input_val = be32toh(pins[4]);
u_int config = be32toh(pins[5]);
if (config & CONFIG_SION)
mux_mode |= IOMUX_CONFIG_SION;
config &= ~CONFIG_SION;
reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, mux_reg);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, mux_reg, mux_mode);
aprint_debug_dev(sc->sc_dev,
"mux offset 0x%08x, val 0x%08x -> 0x%08x\n",
mux_reg, reg, mux_mode);
if (!(config & CONFIG_NO_PAD_CTL)) {
reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, conf_reg);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, conf_reg, config);
aprint_debug_dev(sc->sc_dev,
"config offset 0x%08x, val 0x%08x -> 0x%08x\n",
conf_reg, reg, config);
}
if (__SHIFTOUT(input_val, __BITS(31, 24)) == 0xff) {
uint8_t sel = __SHIFTOUT(input_val, __BITS(7, 0));
uint8_t width = __SHIFTOUT(input_val, __BITS(15, 8));
uint8_t shift = __SHIFTOUT(input_val, __BITS(23, 16));
uint32_t mask = __BITS(shift + (width - 1), shift);
reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, input_reg);
reg &= ~mask;
reg |= __SHIFTIN(sel, mask);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, input_reg, reg);
aprint_debug_dev(sc->sc_dev,
"+input offset 0x%08x, val 0x%08x\n",
input_reg, reg);
} else if (input_reg != 0) {
reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, input_reg);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, input_reg, input_val);
aprint_debug_dev(sc->sc_dev,
"input offset 0x%08x, val 0x%08x -> 0x%08x\n",
input_reg, reg, input_val);
}
pins_len -= 24;
pins += 6;
}
return 0;
}
static struct fdtbus_pinctrl_controller_func imx6_pinctrl_funcs = {
.set_config = imx6_pinctrl_set_config,
};
static int imxiomux_match(device_t, struct cfdata *, void *);
static void imxiomux_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(imxiomux, sizeof(struct imxiomux_softc),
imxiomux_match, imxiomux_attach, NULL, NULL);
static int
imxiomux_match(device_t parent, cfdata_t cf, void *aux)
{
const char * const compatible[] = { "fsl,imx6q-iomuxc", NULL };
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imxiomux_attach(device_t parent, device_t self, void *aux)
{
struct imxiomux_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_addr_t addr;
bus_size_t size;
int error;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get iomux registers\n");
return;
}
sc->sc_dev = self;
sc->sc_iot = faa->faa_bst;
error = bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh);
if (error) {
aprint_error(": couldn't map iomux registers: %d\n", error);
return;
}
aprint_naive("\n");
aprint_normal(": IOMUX Controller\n");
for (int child = OF_child(phandle); child; child = OF_peer(child)) {
for (int sub = OF_child(child); sub; sub = OF_peer(sub)) {
if (!of_hasprop(sub, "fsl,pins"))
continue;
fdtbus_register_pinctrl_config(self, sub, &imx6_pinctrl_funcs);
}
}
fdtbus_pinctrl_configure();
}
/* $NetBSD: imx6_pcie.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_pcie.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_pci.h"
#include "opt_fdt.h"
#include "pci.h"
#include "imxgpio.h"
#include "locators.h"
#define _INTR_PRIVATE
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/extent.h>
#include <sys/queue.h>
#include <sys/mutex.h>
#include <sys/kmem.h>
#include <sys/gpio.h>
#include <machine/frame.h>
#include <arm/cpufunc.h>
#include <dev/fdt/fdtvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pciconf.h>
#include <arm/imx/imxpcievar.h>
#include <arm/imx/imxgpioreg.h>
#include <arm/imx/imxgpiovar.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_iomuxreg.h>
#include <arm/imx/imx6_ccmreg.h>
#include <arm/imx/imx6_ccmvar.h>
struct imxpcie_fdt_softc {
struct imxpcie_softc sc_imxpcie;
struct fdtbus_gpio_pin *sc_pin_reset;
};
static int imx6_pcie_match(device_t, cfdata_t, void *);
static void imx6_pcie_attach(device_t, device_t, void *);
static void imx6_pcie_configure(void *);
static uint32_t imx6_pcie_gpr_read(void *, uint32_t);
static void imx6_pcie_gpr_write(void *, uint32_t, uint32_t);
static void imx6_pcie_reset(void *);
#define IMX6_PCIE_MEM_BASE 0x01000000
#define IMX6_PCIE_MEM_SIZE 0x00f00000 /* 15MB */
#define IMX6_PCIE_ROOT_BASE 0x01f00000
#define IMX6_PCIE_ROOT_SIZE 0x00080000 /* 512KB */
#define IMX6_PCIE_IO_BASE 0x01f80000
#define IMX6_PCIE_IO_SIZE 0x00010000 /* 64KB */
CFATTACH_DECL_NEW(imxpcie_fdt, sizeof(struct imxpcie_fdt_softc),
imx6_pcie_match, imx6_pcie_attach, NULL, NULL);
static const char * const compatible[] = {
"fsl,imx6q-pcie",
NULL
};
static int
imx6_pcie_match(device_t parent, cfdata_t cf, void *aux)
{
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imx6_pcie_attach(device_t parent, device_t self, void *aux)
{
struct imxpcie_fdt_softc * const ifsc = device_private(self);
struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_space_tag_t bst = faa->faa_bst;
char intrstr[128];
bus_addr_t addr;
bus_size_t size;
aprint_naive("\n");
aprint_normal(": PCI Express Controller\n");
sc->sc_dev = self;
sc->sc_iot = bst;
sc->sc_dmat = faa->faa_dmat;
sc->sc_cookie = ifsc;
sc->sc_pci_netbsd_configure = imx6_pcie_configure;
sc->sc_gpr_read = imx6_pcie_gpr_read;
sc->sc_gpr_write = imx6_pcie_gpr_write;
sc->sc_reset = imx6_pcie_reset;
if (fdtbus_get_reg_byname(phandle, "dbi", &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
return;
}
if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
aprint_error_dev(self, "Cannot map registers\n");
return;
}
if (fdtbus_get_reg_byname(phandle, "config", &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
return;
}
sc->sc_root_addr = addr;
sc->sc_root_size = size;
const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
aprint_error_dev(self, "Cannot map registers\n");
return;
}
ifsc->sc_pin_reset = fdtbus_gpio_acquire(phandle, "reset-gpio",
GPIO_PIN_OUTPUT);
if (!ifsc->sc_pin_reset) {
aprint_error(": couldn't acquire reset gpio\n");
return;
}
sc->sc_clk_pcie_axi = fdtbus_clock_get(phandle, "pcie");
if (sc->sc_clk_pcie_axi == NULL) {
aprint_error(": couldn't get clock pcie_axi\n");
return;
}
sc->sc_clk_lvds1_gate = fdtbus_clock_get(phandle, "pcie_bus");
if (sc->sc_clk_lvds1_gate == NULL) {
aprint_error(": couldn't get clock lvds1_gate\n");
return;
}
sc->sc_clk_pcie_ref = fdtbus_clock_get(phandle, "pcie_phy");
if (sc->sc_clk_pcie_ref == NULL) {
aprint_error(": couldn't get clock pcie_ref\n");
return;
}
TAILQ_INIT(&sc->sc_intrs);
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
return;
}
sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM, 0, imxpcie_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "failed to establish interrupt on %s\n",
intrstr);
return;
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
imxpcie_attach_common(sc);
}
static void
imx6_pcie_configure(void *cookie)
{
struct imxpcie_fdt_softc * const ifsc = cookie;
struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
#ifdef PCI_NETBSD_CONFIGURE
struct extent *ioext, *memext;
int error;
ioext = extent_create("pciio", IMX6_PCIE_IO_BASE,
IMX6_PCIE_IO_BASE + IMX6_PCIE_IO_SIZE - 1,
NULL, 0, EX_NOWAIT);
memext = extent_create("pcimem", IMX6_PCIE_MEM_BASE,
IMX6_PCIE_MEM_BASE + IMX6_PCIE_MEM_SIZE - 1,
NULL, 0, EX_NOWAIT);
error = pci_configure_bus(&sc->sc_pc, ioext, memext, NULL, 0,
arm_dcache_align);
extent_destroy(ioext);
extent_destroy(memext);
if (error) {
aprint_error_dev(sc->sc_dev, "configuration failed (%d)\n",
error);
}
#endif
}
static uint32_t
imx6_pcie_gpr_read(void *cookie, uint32_t reg)
{
struct imxpcie_fdt_softc * const ifsc = cookie;
struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
return bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, reg);
}
static void
imx6_pcie_gpr_write(void *cookie, uint32_t reg, uint32_t val)
{
struct imxpcie_fdt_softc * const ifsc = cookie;
struct imxpcie_softc * const sc = &ifsc->sc_imxpcie;
bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, reg, val);
}
static void
imx6_pcie_reset(void *cookie)
{
struct imxpcie_fdt_softc * const ifsc = cookie;
fdtbus_gpio_write(ifsc->sc_pin_reset, 1);
delay(20 * 1000);
fdtbus_gpio_write(ifsc->sc_pin_reset, 0);
}
/* $NetBSD: imx6_platform.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_platform.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_soc.h"
#include "arml2cc.h"
#include "opt_multiprocessor.h"
#include "opt_fdt.h"
#include "opt_fdt_arm.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/fdt/fdtvar.h>
#include <arm/fdt/arm_fdtvar.h>
#include <uvm/uvm_extern.h>
#include <arm/arm32/machdep.h>
#include <machine/bootconfig.h>
#include <arm/cpufunc.h>
#include <arm/cortex/a9tmr_var.h>
#include <arm/cortex/scu_reg.h>
#include <arm/cortex/gic_reg.h>
#include <arm/cortex/pl310_var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_srcreg.h>
#include <arm/imx/imxuartreg.h>
#include <arm/imx/fdt/imx6_platform.h>
#include <libfdt.h>
#define IMX_REF_FREQ 80000000
#ifdef VERBOSE_INIT_ARM
#define VPRINTF(...) printf(__VA_ARGS__)
#else
#define VPRINTF(...) __nothing
#endif
extern struct bus_space armv7_generic_bs_tag;
extern struct bus_space armv7_generic_a4x_bs_tag;
extern struct arm32_bus_dma_tag arm_generic_dma_tag;
static const struct pmap_devmap *
imx_platform_devmap(void)
{
static const struct pmap_devmap devmap[] = {
DEVMAP_ENTRY(KERNEL_IO_IOREG_VBASE, IMX6_IOREG_PBASE, IMX6_IOREG_SIZE),
DEVMAP_ENTRY(KERNEL_IO_ARMCORE_VBASE, IMX6_ARMCORE_PBASE, IMX6_ARMCORE_SIZE),
DEVMAP_ENTRY_END
};
return devmap;
}
static void
imx_platform_init_attach_args(struct fdt_attach_args *faa)
{
faa->faa_bst = &armv7_generic_bs_tag;
faa->faa_a4x_bst = &armv7_generic_a4x_bs_tag;
faa->faa_dmat = &arm_generic_dma_tag;
}
void imx_platform_early_putchar(char);
void
imx_platform_early_putchar(char c)
{
#ifdef CONSADDR
#define CONSADDR_VA ((CONSADDR - IMX6_IOREG_PBASE) + KERNEL_IO_IOREG_VBASE)
volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
(volatile uint32_t *)CONSADDR_VA :
(volatile uint32_t *)CONSADDR;
while ((le32toh(uartaddr[(IMX_USR2/4)]) & IMX_USR2_TXDC) == 0)
;
uartaddr[(IMX_UTXD/4)] = htole32(c);
#endif
}
static void
imx_platform_device_register(device_t self, void *aux)
{
}
static u_int
imx_platform_uart_freq(void)
{
return IMX_REF_FREQ;
}
static void
imx_platform_bootstrap(void)
{
#if NARML2CC > 0
bus_space_tag_t bst = &armv7_generic_bs_tag;
bus_space_handle_t bsh;
if (bus_space_map(bst, IMX6_ARMCORE_PBASE, IMX6_ARMCORE_SIZE, 0, &bsh))
panic("couldn't map armcore registers");
arml2cc_init(bst, bsh, ARMCORE_L2C_BASE);
bus_space_unmap(bst, bsh, IMX6_ARMCORE_SIZE);
#endif
arm_fdt_cpu_bootstrap();
}
static int
imx_platform_mpstart(void)
{
#if defined(MULTIPROCESSOR)
bus_space_tag_t bst = &armv7_generic_bs_tag;
bus_space_handle_t bsh;
if (bus_space_map(bst, IMX6_ARMCORE_PBASE, IMX6_ARMCORE_SIZE, 0, &bsh) != 0)
panic("couldn't map armcore registers");
/* Enable Snoop Control Unit */
bus_space_write_4(bst, bsh, SCU_INV_ALL_REG, 0xff);
bus_space_write_4(bst, bsh, SCU_CTL,
bus_space_read_4(bst, bsh, SCU_CTL) | SCU_CTL_SCU_ENA);
bus_space_unmap(bst, bsh, AIPS1_SRC_SIZE);
if (bus_space_map(bst, IMX6_AIPS1_BASE + AIPS1_SRC_BASE, AIPS1_SRC_SIZE, 0, &bsh) != 0)
panic("couldn't map SRC");
uint32_t srcctl = bus_space_read_4(bst, bsh, SRC_SCR);
const paddr_t mpstart = KERN_VTOPHYS((vaddr_t)cpu_mpstart);
srcctl &= ~(SRC_SCR_CORE1_ENABLE | SRC_SCR_CORE2_ENABLE |
SRC_SCR_CORE3_ENABLE);
bus_space_write_4(bst, bsh, SRC_SCR, srcctl);
for (int i = 1; i < arm_cpu_max; i++) {
bus_space_write_4(bst, bsh, SRC_GPRN_ENTRY(i), mpstart);
srcctl |= SRC_SCR_COREN_RST(i);
srcctl |= SRC_SCR_COREN_ENABLE(i);
}
bus_space_write_4(bst, bsh, SRC_SCR, srcctl);
bus_space_unmap(bst, bsh, AIPS1_SRC_SIZE);
return arm_fdt_cpu_mpstart();
#endif
}
static void
imx6_platform_reset(void)
{
}
const struct arm_platform imx6_platform = {
.ap_devmap = imx_platform_devmap,
.ap_bootstrap = imx_platform_bootstrap,
.ap_init_attach_args = imx_platform_init_attach_args,
.ap_device_register = imx_platform_device_register,
.ap_reset = imx6_platform_reset,
.ap_delay = a9tmr_delay,
.ap_uart_freq = imx_platform_uart_freq,
.ap_mpstart = imx_platform_mpstart,
};
ARM_PLATFORM(imx6, "fsl,imx6q", &imx6_platform);
/* $NetBSD: imx6_platform.h,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _ARM_IMX_FDT_IMX6_PLATFORM_H
#define _ARM_IMX_FDT_IMX6_PLATFORM_H
#include <arch/evbarm/fdt/platform.h>
#define KERNEL_IO_IOREG_VBASE KERNEL_IO_VBASE
#define KERNEL_IO_ARMCORE_VBASE (KERNEL_IO_IOREG_VBASE + IMX6_IOREG_SIZE)
#endif /* _ARM_IMX_FDT_IMX6_PLATFORM_H */
/* $NetBSD: imx6_sdhc.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_sdhc.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/gpio.h>
#include <dev/sdmmc/sdhcreg.h>
#include <dev/sdmmc/sdhcvar.h>
#include <dev/sdmmc/sdmmcvar.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6var.h>
#include <dev/fdt/fdtvar.h>
static int imx6_sdhc_match(device_t, cfdata_t, void *);
static void imx6_sdhc_attach(device_t, device_t, void *);
static int imx6_sdhc_card_detect(struct sdhc_softc *);
struct imx6_sdhc_softc {
struct sdhc_softc sc_sdhc;
bus_space_tag_t sc_bst;
bus_space_handle_t sc_bsh;
bus_size_t sc_bsz;
struct sdhc_host *sc_host;
void *sc_ih;
struct clk *sc_clk_per;
struct fdtbus_gpio_pin *sc_pin_cd;
};
CFATTACH_DECL_NEW(imx6_sdhc, sizeof(struct imx6_sdhc_softc),
imx6_sdhc_match, imx6_sdhc_attach, NULL, NULL);
static const char * const compatible[] = {
"fsl,imx6q-usdhc",
NULL
};
static int
imx6_sdhc_match(device_t parent, cfdata_t cf, void *aux)
{
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imx6_sdhc_attach(device_t parent, device_t self, void *aux)
{
struct imx6_sdhc_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
char intrstr[128];
bus_addr_t addr;
bus_size_t size;
u_int bus_width;
int error;
if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
return;
}
if (of_getprop_uint32(faa->faa_phandle, "bus-width", &bus_width))
bus_width = 4;
sc->sc_clk_per = fdtbus_clock_get(faa->faa_phandle, "per");
if (sc->sc_clk_per == NULL) {
aprint_error(": couldn't get clock\n");
return;
}
sc->sc_sdhc.sc_dev = self;
sc->sc_sdhc.sc_dmat = faa->faa_dmat;
sc->sc_sdhc.sc_clkbase = clk_get_rate(sc->sc_clk_per) / 1000;
sc->sc_sdhc.sc_flags =
SDHC_FLAG_USE_DMA |
SDHC_FLAG_NO_PWR0 |
SDHC_FLAG_HAVE_DVS |
SDHC_FLAG_32BIT_ACCESS |
SDHC_FLAG_8BIT_MODE |
SDHC_FLAG_USE_ADMA2 |
SDHC_FLAG_USDHC;
if (bus_width == 8) {
sc->sc_sdhc.sc_flags |= SDHC_FLAG_8BIT_MODE;
}
sc->sc_sdhc.sc_host = &sc->sc_host;
sc->sc_bst = faa->faa_bst;
error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
if (error) {
aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
return;
}
sc->sc_bsz = size;
sc->sc_pin_cd = fdtbus_gpio_acquire(faa->faa_phandle,
"cd-gpios", GPIO_PIN_INPUT);
if (sc->sc_pin_cd) {
sc->sc_sdhc.sc_vendor_card_detect = imx6_sdhc_card_detect;
sc->sc_sdhc.sc_flags |= SDHC_FLAG_POLL_CARD_DET;
}
error = clk_enable(sc->sc_clk_per);
if (error) {
aprint_error(": couldn't enable clock: %d\n", error);
return;
}
aprint_naive("\n");
aprint_normal(": SDMMC (%u kHz)\n", sc->sc_sdhc.sc_clkbase);
if (sc->sc_sdhc.sc_clkbase == 0) {
aprint_error_dev(self, "couldn't determine frequency\n");
return;
}
if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(self, "failed to decode interrupt\n");
return;
}
sc->sc_ih = fdtbus_intr_establish(faa->faa_phandle, 0, IPL_SDMMC, 0,
sdhc_intr, &sc->sc_sdhc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt on %s\n",
intrstr);
return;
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
error = sdhc_host_found(&sc->sc_sdhc, sc->sc_bst, sc->sc_bsh, sc->sc_bsz);
if (error) {
aprint_error_dev(self, "couldn't initialize host, error = %d\n",
error);
fdtbus_intr_disestablish(faa->faa_phandle, sc->sc_ih);
sc->sc_ih = NULL;
return;
}
}
static int
imx6_sdhc_card_detect(struct sdhc_softc *ssc)
{
struct imx6_sdhc_softc *sc = device_private(ssc->sc_dev);
KASSERT(sc->sc_pin_cd != NULL);
return fdtbus_gpio_read(sc->sc_pin_cd);
}
/* $NetBSD: imx6_usb.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: imx6_usb.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include <locators.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/intr.h>
#include <sys/bus.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_mem.h>
#include <dev/usb/ehcireg.h>
#include <dev/usb/ehcivar.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_usbreg.h>
#include <arm/imx/imxusbvar.h>
#include <dev/fdt/fdtvar.h>
struct imxusbc_fdt_softc {
struct imxusbc_softc sc_imxusbc; /* Must be first */
int sc_phandle;
};
static int imx6_usb_match(device_t, struct cfdata *, void *);
static void imx6_usb_attach(device_t, device_t, void *);
static int imx6_usb_init_clocks(struct imxusbc_softc *);
static void imx6_usb_init(struct imxehci_softc *);
static void init_otg(struct imxehci_softc *);
static void init_h1(struct imxehci_softc *);
static int imxusbc_print(void *, const char *);
static void *imx6_usb_intr_establish(struct imxehci_softc *);
/* attach structures */
CFATTACH_DECL_NEW(imxusbc_fdt, sizeof(struct imxusbc_fdt_softc),
imx6_usb_match, imx6_usb_attach, NULL, NULL);
static const char * const compatible[] = {
"fsl,imx6q-usb",
NULL
};
static int
imx6_usb_match(device_t parent, cfdata_t cf, void *aux)
{
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imx6_usb_attach(device_t parent, device_t self, void *aux)
{
struct imxusbc_fdt_softc *ifsc = device_private(self);
struct imxusbc_softc *sc = &ifsc->sc_imxusbc;
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_space_tag_t bst = faa->faa_bst;
bus_space_handle_t bsh;
bus_addr_t addr;
bus_size_t size;
int error;
aprint_naive("\n");
aprint_normal("\n");
ifsc->sc_phandle = phandle;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get imxusbc registers\n");
return;
}
error = bus_space_map(bst, addr, size, 0, &bsh);
if (error) {
aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
return;
}
sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
if (sc->sc_clk == NULL) {
aprint_error(": couldn't get clock\n");
return;
}
sc->sc_init_md_hook = imx6_usb_init;
sc->sc_intr_establish_md_hook = imx6_usb_intr_establish;
sc->sc_setup_md_hook = NULL;
sc->sc_dev = self;
sc->sc_iot = bst;
sc->sc_ioh = bsh;
sc->sc_ehci_size = size;
sc->sc_ehci_offset = 0;
struct fdt_phandle_data data;
error = fdtbus_get_phandle_with_data(phandle, "fsl,usbmisc",
"#index-cells", 0, &data);
if (error) {
aprint_error(": couldn't get usbmisc property\n");
return;
}
int unit = be32toh(data.values[0]);
if (fdtbus_get_reg(data.phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get usbmisc registers\n");
return;
}
error = bus_space_map(bst, addr, size, 0, &bsh);
if (error) {
aprint_error(": couldn't map usbmisc registers: %d\n", error);
return;
}
sc->sc_ioh_usbnc = bsh;
if (imx6_usb_init_clocks(sc) != 0) {
aprint_error_dev(self, "couldn't init clocks\n");
return;
}
/* attach OTG/EHCI host controllers */
struct imxusbc_attach_args iaa;
iaa.aa_iot = sc->sc_iot;
iaa.aa_ioh = sc->sc_ioh;
iaa.aa_dmat = faa->faa_dmat;
iaa.aa_unit = unit;
iaa.aa_irq = IMXUSBCCF_IRQ_DEFAULT;
config_found_sm_loc(self, "imxusbc", NULL, &iaa, imxusbc_print, NULL);
return;
}
static int
imxusbc_print(void *aux, const char *name __unused)
{
struct imxusbc_attach_args *iaa;
iaa = (struct imxusbc_attach_args *)aux;
aprint_normal(" unit %d intr %d", iaa->aa_unit, iaa->aa_irq);
return UNCONF;
}
static int
imx6_usb_init_clocks(struct imxusbc_softc *sc)
{
int error;
error = clk_enable(sc->sc_clk);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error);
return error;
}
return 0;
}
static void
imx6_usb_init(struct imxehci_softc *sc)
{
switch (sc->sc_unit) {
case 0: /* OTG controller */
init_otg(sc);
break;
case 1: /* EHCI Host 1 */
init_h1(sc);
break;
case 2: /* EHCI Host 2 */
case 3: /* EHCI Host 3 */
default:
aprint_error_dev(sc->sc_dev, "unit %d not supported\n",
sc->sc_unit);
}
}
static void
init_otg(struct imxehci_softc *sc)
{
struct imxusbc_softc *usbc = sc->sc_usbc;
uint32_t v;
sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE;
imxehci_reset(sc);
v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_OTG_CTRL);
v |= USBNC_USB_OTG_CTRL_WKUP_VBUS_EN;
v |= USBNC_USB_OTG_CTRL_OVER_CUR_DIS;
v |= USBNC_USB_OTG_CTRL_PWR_POL;
v &= ~USBNC_USB_OTG_CTRL_UTMI_ON_CLOCK;
bus_space_write_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_OTG_CTRL, v);
}
static void
init_h1(struct imxehci_softc *sc)
{
struct imxusbc_softc *usbc = sc->sc_usbc;
uint32_t v;
sc->sc_iftype = IMXUSBC_IF_UTMI_WIDE;
v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_UH1_CTRL);
v |= USBNC_USB_UH1_CTRL_OVER_CUR_POL;
v |= USBNC_USB_UH1_CTRL_OVER_CUR_DIS;
bus_space_write_4(usbc->sc_iot, usbc->sc_ioh_usbnc, USBNC_USB_UH1_CTRL, v);
/* do reset */
imxehci_reset(sc);
/* set mode */
v = bus_space_read_4(usbc->sc_iot, usbc->sc_ioh, USBC_UH1_USBMODE);
v &= ~USBC_UH_USBMODE_CM;
v |= __SHIFTIN(USBC_UH_USBMODE_CM, USBC_UH_USBMODE_CM_HOST_CONTROLLER);
bus_space_write_4(usbc->sc_iot, usbc->sc_ioh, USBC_UH1_USBMODE, v);
}
static void *
imx6_usb_intr_establish(struct imxehci_softc *sc)
{
struct imxusbc_fdt_softc *ifsc = (struct imxusbc_fdt_softc *)sc->sc_usbc;
ehci_softc_t *hsc = &sc->sc_hsc;
void *ih;
char intrstr[128];
if (!fdtbus_intr_str(ifsc->sc_phandle, 0, intrstr, sizeof(intrstr))) {
aprint_error_dev(sc->sc_dev, "failed to decode interrupt\n");
return NULL;
}
ih = fdtbus_intr_establish(ifsc->sc_phandle, 0, IPL_USB, 0, ehci_intr, hsc);
if (ih == NULL) {
aprint_error_dev(sc->sc_dev, "failed to establish interrupt on %s\n",
intrstr);
return NULL;
}
aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr);
return ih;
}
/* $NetBSD: imx6_usbphy.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $ */
/*-
* Copyright (c) 2019 Genetec Corporation. All rights reserved.
* Written by Hashimoto Kenichi for Genetec Corporation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: imx6_usbphy.c,v 1.1 2019/07/24 13:12:33 hkenken Exp $");
#include "opt_fdt.h"
#include "locators.h"
#include "ohci.h"
#include "ehci.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <arm/imx/imx6var.h>
#include <arm/imx/imx6_reg.h>
#include <arm/imx/imx6_usbphyreg.h>
#include <dev/fdt/fdtvar.h>
struct imx6_usbphy_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
struct clk *sc_clk;
};
static int imx6_usbphy_match(device_t, cfdata_t, void *);
static void imx6_usbphy_attach(device_t, device_t, void *);
static int imx6_usbphy_init_clocks(device_t);
static int imx6_usbphy_enable(device_t, void *, bool);
CFATTACH_DECL_NEW(imxusbphy, sizeof(struct imx6_usbphy_softc),
imx6_usbphy_match, imx6_usbphy_attach, NULL, NULL);
static const char * const compatible[] = {
"fsl,imx6q-usbphy",
NULL
};
static int
imx6_usbphy_match(device_t parent, cfdata_t cf, void *aux)
{
struct fdt_attach_args * const faa = aux;
return of_match_compatible(faa->faa_phandle, compatible);
}
static void
imx6_usbphy_attach(device_t parent, device_t self, void *aux)
{
struct imx6_usbphy_softc *sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
bus_space_tag_t bst = faa->faa_bst;
bus_space_handle_t bsh;
bus_addr_t addr;
bus_size_t size;
int error;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get iomux registers\n");
return;
}
error = bus_space_map(bst, addr, size, 0, &bsh);
if (error) {
aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error);
return;
}
sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
if (sc->sc_clk == NULL) {
aprint_error(": couldn't get clock\n");
return;
}
sc->sc_dev = self;
sc->sc_iot = bst;
sc->sc_ioh = bsh;
aprint_naive("\n");
aprint_normal(": USB PHY\n");
imx6_usbphy_init_clocks(self);
imx6_usbphy_enable(self, NULL, true);
}
static int
imx6_usbphy_init_clocks(device_t dev)
{
struct imx6_usbphy_softc * const sc = device_private(dev);
int error;
error = clk_enable(sc->sc_clk);
if (error) {
aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error);
return error;
}
return 0;
}
#define USBPHY_READ(sc, reg) \
bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
#define USBPHY_WRITE(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
static int
imx6_usbphy_enable(device_t dev, void *priv, bool enable)
{
struct imx6_usbphy_softc * const sc = device_private(dev);
/* USBPHY enable */
USBPHY_WRITE(sc, USBPHY_CTRL, USBPHY_CTRL_CLKGATE);
/* do reset */
USBPHY_WRITE(sc, USBPHY_CTRL_SET, USBPHY_CTRL_SFTRST);
delay(100);
/* clear reset, and run clocks */
USBPHY_WRITE(sc, USBPHY_CTRL_CLR,
USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE);
delay(100);
/* power on */
USBPHY_WRITE(sc, USBPHY_PWD, 0);
/* UTMI+Level2, Level3 */
USBPHY_WRITE(sc, USBPHY_CTRL_SET,
USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3);
return 0;
}
#
# $NetBSD: IMX,v 1.1 2019/07/24 13:12:34 hkenken Exp $
#
# NXP(Freescale) I.MX family SoCs
#
include "arch/evbarm/conf/std.imx"
include "arch/evbarm/conf/files.imx"
include "arch/evbarm/conf/GENERIC.common"
makeoptions DTSGNUARCH="arm"
makeoptions DTSSUBDIR="fsl"
makeoptions DTS="
imx6q-hummingboard.dts
imx6dl-hummingboard.dts
imx6q-hummingboard2.dts
imx6dl-hummingboard2.dts
"
options MULTIPROCESSOR
options CPU_CORTEXA9
options SOC_IMX6Q
options SOC_IMX6DL
options SOC_IMX6QDL
pseudo-device openfirm # /dev/openfirm
#options DIAGNOSTIC # internal consistency checks
#options DEBUG
#options LOCKDEBUG
#options PMAP_DEBUG # Enable pmap_debug_level code
#options IPKDB # remote kernel debugging
#options VERBOSE_INIT_ARM # verbose bootstrapping messages
# CONSADDR is required for early init messages from VERBOSE_INIT_ARM.
options CONSADDR=0x02020000
options EARLYCONS=imx
options BOOT_ARGS="\"verbose debug\""
makeoptions DEBUG="-g" # compile full symbol table
makeoptions COPY_SYMTAB=1
config netbsd root on ? type ?
# Device tree support
armfdt0 at root
simplebus* at fdt? pass 0
# CPUs
cpus* at fdt? pass 0
cpu* at fdt? pass 0
# Timer
a9tmr* at fdt? pass 2 # A9 Global Timer
arma9tmr0 at a9tmr?
# Interrupt controller
gic* at fdt? pass 1 # ARM Generic Interrupt Controller
armgic0 at gic?
l2cc* at fdt? pass 1 # ARM Cortex A9 L2 Cache Controller
arml2cc* at l2cc?
# Clock
fclock* at fdt? pass 1
ffclock* at fdt? pass 1
fregulator* at fdt? pass 5
gregulator* at fdt? pass 4
imxccm* at fdt? pass 1 # i.MX6 ccm
# IOMUX
imxiomux* at fdt? pass 2
# GPC
imxgpc* at fdt? pass 2
# GPIO
imxgpio* at fdt? pass 3
gpio* at gpiobus?
# UART
imxuart* at fdt?
options IMXUARTCONSOLE
# Network Interfaces
enet* at fdt? # FEC
# MII/PHY support
atphy* at mii? phy ? # Attansic/Atheros PHYs
ukphy* at mii? phy ? # generic unknown PHYs
# SATA
ahcisata* at fdt? # SATA
atabus* at ahcisata? channel ?
wd* at atabus? drive ?
# ATAPI bus support
atapibus* at atapi?
# ATAPI devices
# flags have the same meaning as for IDE drives.
cd* at atapibus? drive ? flags 0x0000 # ATAPI CD-ROM drives
sd* at atapibus? drive ? flags 0x0000 # ATAPI disk drives
st* at atapibus? drive ? flags 0x0000 # ATAPI tape drives
uk* at atapibus? drive ? flags 0x0000 # ATAPI unknown
# SDMMC
sdhc* at fdt? # SDMMC
sdmmc* at sdhc?
ld* at sdmmc?
# USB
imxusbphy* at fdt?
imxusbc* at fdt?
ehci* at imxusbc?
usb* at ehci?
# USB device drivers
include "dev/usb/usbdevices.config"
midi* at midibus?
# PCIe
imxpcie* at fdt?
#options PCIVERBOSE
#options PCI_CONFIG_DUMP
pci* at imxpcie?
ppb* at pci? dev ? function ?
pci* at ppb?
cinclude "arch/evbarm/conf/IMX.local"
# $NetBSD: files.imx,v 1.1 2019/07/24 13:12:34 hkenken Exp $
#
# NXP(Freescale) i.MX configuration info
#
include "arch/arm/pic/files.pic"
include "arch/arm/cortex/files.cortex"
include "arch/evbarm/conf/files.fdt"
include "arch/arm/imx/fdt/files.imx6"
# $NetBSD: mk.imx,v 1.1 2019/07/24 13:12:34 hkenken Exp $
.if !empty(MACHINE_ARCH:M*eb)
EXTRA_LINKFLAGS+= --be8
.endif
ENTRYPOINT= generic_start
SYSTEM_FIRST_OBJ= armv6_start.o
SYSTEM_FIRST_SFILE= ${ARM}/arm/armv6_start.S
_OSRELEASE!= ${HOST_SH} $S/conf/osrelease.sh
MKUBOOTIMAGEARGS= -A arm -T kernel -O linux
MKUBOOTIMAGEARGS+= -e 0
MKUBOOTIMAGEARGS+= -n "NetBSD/${BOARDTYPE:U${MACHINE_ARCH}} ${_OSRELEASE}"
MKUBOOTIMAGEARGS+= -a $(KERNEL_BASE_PHYS) -e $(KERNEL_BASE_PHYS)
MKUBOOTIMAGEARGS_NONE= ${MKUBOOTIMAGEARGS} -C none
MKUBOOTIMAGEARGS_GZ= ${MKUBOOTIMAGEARGS} -C gz
SYSTEM_LD_TAIL_EXTRA+=; \
echo ${OBJCOPY} -S -O binary $@ $@.bin; \
${OBJCOPY} -S -O binary $@ $@.bin; \
echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \
${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \
echo ${TOOL_GZIP} -c $@.bin > $@.bin.gz; \
${TOOL_GZIP} -c $@.bin > $@.bin.gz; \
echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub; \
${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin@}
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.ub@}
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin.gz@}
EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.gz.ub@}
# $NetBSD: std.imx,v 1.1 2019/07/24 13:12:34 hkenken Exp $
#
machine evbarm arm
include "arch/arm/conf/std.arm" # arch standard options
include "arch/evbarm/conf/std.evbarm"
# Architecture opions
options ARM_GENERIC_TODR
options ARM_HAS_VBAR
options ARM_INTR_IMPL="<arch/arm/fdt/fdt_intr.h>"
options DRAM_BLOCKS=256
options EVBARM_BOARDTYPE="evbarm"
options FDT # Flattened Device Tree support
options FPU_VFP
options MODULAR
options MODULAR_DEFAULT_AUTOLOAD
options PCI_NETBSD_CONFIGURE
options TPIDRPRW_IS_CURCPU
options __BUS_SPACE_HAS_STREAM_METHODS
options __HAVE_CPU_COUNTER
options __HAVE_CPU_UAREA_ALLOC_IDLELWP
options __HAVE_GENERIC_START
options __HAVE_GENERIC_CPU_INITCLOCKS
options __HAVE_FAST_SOFTINTS # should be in types.h
options __HAVE_PCI_CONF_HOOK
#options __HAVE_PCI_MSI_MSIX
makeoptions BOARDMKFRAG="${THISARM}/conf/mk.imx"
makeoptions KERNEL_BASE_PHYS="0x18000000"
makeoptions KERNEL_BASE_VIRT="0x80000000"