diff --git a/sys/arm/arm/pmu.c b/sys/arm/arm/pmu.c --- a/sys/arm/arm/pmu.c +++ b/sys/arm/arm/pmu.c @@ -121,6 +121,7 @@ "Unable to setup interrupt handler.\n"); goto fail; } +#ifdef SMP if (sc->irq[i].cpuid != -1) { err = bus_bind_intr(dev, sc->irq[i].res, sc->irq[i].cpuid); @@ -130,6 +131,7 @@ goto fail; } } +#endif } #if defined(__arm__) && (__ARM_ARCH > 6) diff --git a/sys/arm/arm/pmu_fdt.c b/sys/arm/arm/pmu_fdt.c --- a/sys/arm/arm/pmu_fdt.c +++ b/sys/arm/arm/pmu_fdt.c @@ -151,6 +151,10 @@ goto done; } +#ifndef SMP + return 0; +#endif + /* Check if PMU have one per-CPU interrupt */ if (intr_is_per_cpu(sc->irq[0].res)) { if (has_affinity) { diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC --- a/sys/arm/conf/GENERIC +++ b/sys/arm/conf/GENERIC @@ -60,6 +60,7 @@ options SOC_MV_ARMADAXP options SOC_TI_AM335X options SOC_OMAP4 +options SOC_IMX6 options SCHED_ULE # ULE scheduler options SMP # Enable multiple cores diff --git a/sys/arm/conf/SBC_EC9100 b/sys/arm/conf/SBC_EC9100 new file mode 100644 --- /dev/null +++ b/sys/arm/conf/SBC_EC9100 @@ -0,0 +1,168 @@ +# +# SBC_EC9100 -- Kernel config for EMTOP-TECH (Formerly Embest) SBC-EC9100 +# Board available at https://www.amazon.com/derp/dp/B0BHQMZGS2/ +# +# For more information on this file, please read the config(5) manual page, +# and/or the handbook section on Kernel Configuration Files: +# +# https://docs.freebsd.org/en/books/handbook/kernelconfig/#kernelconfig-config +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident SBC_EC9100 + +cpu CPU_CORTEXA +machine arm armv7 +makeoptions CONF_CFLAGS="-march=armv7a" + +include "std.armv7" +files "../freescale/imx/files.imx6" + +nooptions cam +nodevice cam +options SOC_IMX6 +options SCHED_ULE # ULE scheduler +options PLATFORM +options LINUX_BOOT_ABI + +# pseudo devices +device clk +device phy +device hwreset +device nvmem +device regulator +device syscon + +# CPU frequency control +device cpufreq + +# Interrupt controller +device gic + +# PMU support (for CCNT). +device pmu + +# ARM Generic Timer +device generic_timer +device mpcore_timer + +# MMC/SD/SDIO Card slot support +device sdhci # SD controller +device mmc # mmc/sd bus +device mmcsd # mmc/sd flash cards + +# Console and misc +device uart +device md # Memory "disks" +device firmware # firmware assist module +device pl310 # PL310 L2 cache controller + +# I2C support +device iicbus +device iic +device fsliic # Freescale i2c/iic + +# i2c RTCs +device nxprtc # NXP RTCs: PCA/PFC212x PCA/PCF85xx + +# GPIO +device gpio +device gpiobacklight +device gpioled +device gpioregulator + +# EVDEV support +device evdev # input event device support +options EVDEV_SUPPORT # evdev support in legacy drivers +device uinput # install /dev/uinput cdev + +# SPI +device spibus +device spigen + +# PWM +device pwm + +# Watchdog support +# If we don't enable the watchdog driver, the BeagleBone could potentially +# reboot automatically because the boot loader might have enabled the +# watchdog. +device imxwdt # Watchdog. WARNING: can't be disabled!!! + +device scbus # SCSI bus (required for ATA/SCSI) +device da # Direct Access (disks) +#device cd # CD +#device pass # Passthrough device (direct ATA/SCSI access) + +# USB support +options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. +device usb +device uhci +device ohci +device ehci +device xhci +#device musb + +device axe # USB-Ethernet +#device umass # Disks/Mass storage - Requires scbus and da +device uhid # "Human Interface Devices" +device ukbd # Allow keyboard like HIDs to control console + +# Device mode support +device usb_template # Control of the gadget + +# Ethernet +device loop +device ether +device vlan # 802.1Q VLAN support +device bpf +device mii +device mdio + +# Ethernet NICs that use the common MII bus controller code. +# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! +device miibus + +device ffec # Freescale Fast Ethernet Controller + +# Sound support +#device sound + +# Pinmux +device fdt_pinctrl + +# DMA controller +device fslsdma + +# Extensible Firmware Interface +options EFI + +# RTC +device imx6_snvs # IMX6 On-chip RTC + +# HID support +device hid # Generic HID support + +# Others from files.imx6 +device imx_gpt +device imx_spi + +# New stuff +device vf_adc + +# Flattened Device Tree +options FDT # Configure using FDT/DTB data +makeoptions MODULES_EXTRA+="dtb/imx6" + +# SOC-specific modules +makeoptions MODULES_EXTRA+="imx" diff --git a/sys/arm/freescale/fsl_ocotp.c b/sys/arm/freescale/fsl_ocotp.c --- a/sys/arm/freescale/fsl_ocotp.c +++ b/sys/arm/freescale/fsl_ocotp.c @@ -47,6 +47,7 @@ #include #include +#include /* * Find the physical address and size of the ocotp registers and devmap them, @@ -63,6 +64,14 @@ #include #include +/* + * Table of CPU max frequencies. This is used to translate the max frequency + * value (0-3) from the ocotp CFG3 register into a mhz value that can be looked + * up in the operating points table. + */ +static uint32_t imx6q_ocotp_mhz_tab[] = {792, 852, 996, 1200}; +static uint32_t imx6ul_ocotp_mhz_tab[] = {0, 528, 696, 0}; + static uint32_t *ocotp_regs; static vm_size_t ocotp_size; @@ -75,7 +84,8 @@ if ((root = OF_finddevice("/")) == -1) goto fatal; if ((child = fdt_depth_search_compatible(root, "fsl,imx6q-ocotp", 0)) == 0) - goto fatal; + if ((child = fdt_depth_search_compatible(root, "fsl,imx6ul-ocotp", 0)) == 0) + goto fatal; if (fdt_regsize(child, &base, &size) != 0) goto fatal; @@ -149,12 +159,12 @@ static int ocotp_probe(device_t dev) { - if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "fsl,imx6q-ocotp") == 0) - return (ENXIO); + if (ofw_bus_is_compatible(dev, "fsl,imx6ul-ocotp") == 0) + return (ENXIO); device_set_desc(dev, "Freescale On-Chip One-Time-Programmable Memory"); @@ -162,7 +172,7 @@ return (BUS_PROBE_DEFAULT); } -uint32_t +static uint32_t fsl_ocotp_read_4(bus_size_t off) { @@ -185,6 +195,41 @@ return (ocotp_regs[off / 4]); } +uint32_t +fsl_ocotp_get_max_mhz(void) +{ + uint32_t cfg3speed; + + /* + * Get the maximum speed this cpu can be set to. The values in the + * OCOTP CFG3 register are not documented in the reference manual. + * The following info was in an archived email found via web search: + * - 2b'11: 1200000000Hz; + * - 2b'10: 996000000Hz; + * - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. + * - 2b'00: 792000000Hz; + * The default hardware max speed can be overridden by a tunable. + */ + cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & + FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT; + if (imx_soc_type() == IMXSOC_6UL) + return imx6ul_ocotp_mhz_tab[cfg3speed]; + else + return imx6q_ocotp_mhz_tab[cfg3speed]; + return 0; +} + +void +fsl_ocotp_get_temp_calibration(uint32_t *room_cnt, uint32_t *high_cnt, uint32_t *high_val) +{ + uint32_t cal; + + cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1); + *room_cnt = (cal & 0xFFF00000) >> 20; + *high_cnt = (cal & 0x000FFF00) >> 8; + *high_val = (cal & 0x000000FF) * 10; +} + static device_method_t ocotp_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ocotp_probe), diff --git a/sys/arm/freescale/fsl_ocotpvar.h b/sys/arm/freescale/fsl_ocotpvar.h --- a/sys/arm/freescale/fsl_ocotpvar.h +++ b/sys/arm/freescale/fsl_ocotpvar.h @@ -31,6 +31,7 @@ #ifndef FSL_OCOTPVAR_H #define FSL_OCOTPVAR_H -uint32_t fsl_ocotp_read_4(bus_size_t _offset); +uint32_t fsl_ocotp_get_max_mhz(void); +void fsl_ocotp_get_temp_calibration(uint32_t *room_cnt, uint32_t *high_cnt, uint32_t *high_val); #endif diff --git a/sys/arm/freescale/imx/files.imx6 b/sys/arm/freescale/imx/files.imx6 --- a/sys/arm/freescale/imx/files.imx6 +++ b/sys/arm/freescale/imx/files.imx6 @@ -4,6 +4,7 @@ # Standard imx6 devices and support. # arm/freescale/fsl_ocotp.c standard +arm/freescale/vybrid/vf_adc.c optional vf_adc arm/freescale/imx/imx6_anatop.c standard arm/freescale/imx/imx6_ccm.c standard arm/freescale/imx/imx6_machdep.c standard diff --git a/sys/arm/freescale/imx/imx6_anatop.c b/sys/arm/freescale/imx/imx6_anatop.c --- a/sys/arm/freescale/imx/imx6_anatop.c +++ b/sys/arm/freescale/imx/imx6_anatop.c @@ -110,6 +110,7 @@ uint32_t temp_throttle_reset_cnt; uint32_t temp_throttle_trigger_cnt; uint32_t temp_throttle_val; + boolean_t irq_fired; }; static struct imx6_anatop_softc *imx6_anatop_sc; @@ -122,10 +123,12 @@ * more than 200mV, and the minimum SOC voltage is 1150mV, so that * dictates the 950mV entry in this table. */ -static struct oppt { +struct oppt { uint32_t mhz; uint32_t mv; -} imx6_oppt_table[] = { +}; + +static struct oppt imx6_oppt_table[] = { { 396, 950}, { 792, 1150}, { 852, 1225}, @@ -133,12 +136,11 @@ {1200, 1275}, }; -/* - * Table of CPU max frequencies. This is used to translate the max frequency - * value (0-3) from the ocotp CFG3 register into a mhz value that can be looked - * up in the operating points table. - */ -static uint32_t imx6_ocotp_mhz_tab[] = {792, 852, 996, 1200}; +static struct oppt imx6ul_oppt_table[] = { + {528, 1150}, + {396, 1000}, + {198, 950}, +}; #define TZ_ZEROC 2731 /* deci-Kelvin <-> deci-Celsius offset. */ @@ -258,20 +260,30 @@ cpufreq_nearest_oppt(struct imx6_anatop_softc *sc, uint32_t cpu_newmhz) { int d, diff, i, nearest; + static struct oppt *tbl; + int tblsz; + if (imx_soc_type() == IMXSOC_6UL) { + tbl = imx6ul_oppt_table; + tblsz = nitems(imx6ul_oppt_table); + } + else { + tbl = imx6_oppt_table; + tblsz = nitems(imx6_oppt_table); + } if (cpu_newmhz > sc->cpu_maxmhz_hw && !sc->cpu_overclock_enable) cpu_newmhz = sc->cpu_maxmhz_hw; diff = INT_MAX; nearest = 0; - for (i = 0; i < nitems(imx6_oppt_table); ++i) { - d = abs((int)cpu_newmhz - (int)imx6_oppt_table[i].mhz); + for (i = 0; i < tblsz; ++i) { + d = abs((int)cpu_newmhz - (int)tbl[i].mhz); if (diff > d) { diff = d; nearest = i; } } - return (&imx6_oppt_table[nearest]); + return (&tbl[nearest]); } static void @@ -392,7 +404,6 @@ static void cpufreq_initialize(struct imx6_anatop_softc *sc) { - uint32_t cfg3speed; struct oppt * op; SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_imx), @@ -435,9 +446,7 @@ * - 2b'00: 792000000Hz; * The default hardware max speed can be overridden by a tunable. */ - cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & - FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT; - sc->cpu_maxmhz_hw = imx6_ocotp_mhz_tab[cfg3speed]; + sc->cpu_maxmhz_hw = fsl_ocotp_get_max_mhz(); sc->cpu_maxmhz = sc->cpu_maxmhz_hw; TUNABLE_INT_FETCH("hw.imx6.cpu_minmhz", &sc->cpu_minmhz); @@ -550,18 +559,49 @@ } } +static void +tempmon_apply_speed(struct imx6_anatop_softc *sc) +{ + /* Lower counts are higher temperatures. */ + if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt) + tempmon_goslow(sc); + else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt)) + tempmon_gofast(sc); +} + static int tempmon_intr(void *arg) { struct imx6_anatop_softc *sc = arg; + uint32_t misc1; /* * XXX Note that this code doesn't currently run (for some mysterious * reason we just never get an interrupt), so the real monitoring is * done by tempmon_throttle_check(). + * XXX Runs for me, 14-CURRENT July 26, 2023 - shurd@ + * I've made it so the callout stops being scheduled if the intr fires */ - tempmon_goslow(sc); + sc->irq_fired = true; + temp_update_count(sc); + misc1 = imx6_anatop_read_4(IMX6_ANALOG_PMU_MISC1); + if (misc1 & IMX6_ANALOG_PMU_MISC1_IRQ_TEMPPANIC) + panic("Temperature panic triggered\n"); + // Clear the interrupt + misc1 &= ~(IMX6_ANALOG_PMU_MISC1_IRQ_TEMPHIGH | IMX6_ANALOG_PMU_MISC1_IRQ_TEMPLOW); + imx6_anatop_write_4(IMX6_ANALOG_PMU_MISC1, misc1); + + if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt) { + sc->temp_last_cnt = sc->temp_throttle_reset_cnt + 1; + tempmon_gofast(sc); + } + else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt)) { + sc->temp_last_cnt = sc->temp_throttle_trigger_cnt - 1; + tempmon_goslow(sc); + } + // Clear the interrupt /* XXX Schedule callout to speed back up eventually. */ + return (FILTER_HANDLED); } @@ -570,30 +610,21 @@ { struct imx6_anatop_softc *sc = arg; - /* Lower counts are higher temperatures. */ - if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt) - tempmon_goslow(sc); - else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt)) - tempmon_gofast(sc); - - callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, - 0, tempmon_throttle_check, sc, 0); + tempmon_apply_speed(sc); + if (!sc->irq_fired) + callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, + 0, tempmon_throttle_check, sc, 0); } static void initialize_tempmon(struct imx6_anatop_softc *sc) { - uint32_t cal; - /* * Fetch calibration data: a sensor count at room temperature (25C), * a sensor count at a high temperature, and that temperature */ - cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1); - sc->temp_room_cnt = (cal & 0xFFF00000) >> 20; - sc->temp_high_cnt = (cal & 0x000FFF00) >> 8; - sc->temp_high_val = (cal & 0x000000FF) * 10; + fsl_ocotp_get_temp_calibration(&sc->temp_room_cnt, &sc->temp_high_cnt, &sc->temp_high_val); /* * Throttle to a lower cpu freq at 10C below the "hot" temperature, and @@ -614,6 +645,11 @@ (sc->temp_throttle_trigger_cnt << IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) | IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE); + imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE2, + ((sc->temp_high_val & IMX6_ANALOG_TEMPMON_TEMPSENSE2_VALUE_MASK) << + IMX6_ANALOG_TEMPMON_TEMPSENSE2_PANIC_SHIFT) | + (IMX6_ANALOG_TEMPMON_TEMPSENSE2_VALUE_MASK << + IMX6_ANALOG_TEMPMON_TEMPSENSE2_LOW_SHIFT)); /* * XXX Note that the alarm-interrupt feature isn't working yet, so diff --git a/sys/arm/freescale/imx/imx6_anatopreg.h b/sys/arm/freescale/imx/imx6_anatopreg.h --- a/sys/arm/freescale/imx/imx6_anatopreg.h +++ b/sys/arm/freescale/imx/imx6_anatopreg.h @@ -112,7 +112,9 @@ #define IMX6_ANALOG_PMU_MISC1_SET 0x164 #define IMX6_ANALOG_PMU_MISC1_CLR 0x168 #define IMX6_ANALOG_PMU_MISC1_TOG 0x16C -#define IMX6_ANALOG_PMU_MISC1_IRQ_TEMPSENSE (1 << 29) +#define IMX6_ANALOG_PMU_MISC1_IRQ_TEMPHIGH (1 << 29) +#define IMX6_ANALOG_PMU_MISC1_IRQ_TEMPLOW (1 << 28) +#define IMX6_ANALOG_PMU_MISC1_IRQ_TEMPPANIC (1 << 27) #define IMX6_ANALOG_PMU_MISC2 0x170 #define IMX6_ANALOG_PMU_MISC2_SET 0x174 @@ -153,6 +155,11 @@ #define IMX6_ANALOG_TEMPMON_TEMPSENSE1_CLR 0x198 #define IMX6_ANALOG_TEMPMON_TEMPSENSE1_TOG 0x19C +#define IMX6_ANALOG_TEMPMON_TEMPSENSE2 0x290 +#define IMX6_ANALOG_TEMPMON_TEMPSENSE2_VALUE_MASK 0xFFF +#define IMX6_ANALOG_TEMPMON_TEMPSENSE2_PANIC_SHIFT 16 +#define IMX6_ANALOG_TEMPMON_TEMPSENSE2_LOW_SHIFT 0 + #define IMX6_ANALOG_USB1_VBUS_DETECT 0x1A0 #define IMX6_ANALOG_USB1_VBUS_DETECT_SET 0x1A4 #define IMX6_ANALOG_USB1_VBUS_DETECT_CLR 0x1A8 diff --git a/sys/arm/freescale/imx/imx6_ccm.c b/sys/arm/freescale/imx/imx6_ccm.c --- a/sys/arm/freescale/imx/imx6_ccm.c +++ b/sys/arm/freescale/imx/imx6_ccm.c @@ -51,6 +51,12 @@ #include #include +#include +#include +#include + +#include "syscon_if.h" + #ifndef CCGR_CLK_MODE_ALWAYS #define CCGR_CLK_MODE_OFF 0 #define CCGR_CLK_MODE_RUNMODE 1 @@ -64,6 +70,8 @@ static struct ccm_softc *ccm_sc; +static int imx6ul_ccm_enet_enable(uint32_t div); + static inline uint32_t RD4(struct ccm_softc *sc, bus_size_t off) { @@ -91,41 +99,66 @@ ccm_init_gates(struct ccm_softc *sc) { uint32_t reg; + u_int soc = imx_soc_type(); - /* ahpbdma, aipstz 1 & 2 buses */ - reg = CCGR0_AIPS_TZ1 | CCGR0_AIPS_TZ2 | CCGR0_ABPHDMA; + if (soc == IMXSOC_6UL) + reg = 0xffffffff; + else + /* ahpbdma, aipstz 1 & 2 buses */ + reg = CCGR1_ENET | CCGR1_EPIT1 | CCGR1_GPT | CCGR1_ECSPI1 | + CCGR1_ECSPI2 | CCGR1_ECSPI3 | CCGR1_ECSPI4 | CCGR1_ECSPI5; WR4(sc, CCM_CCGR0, reg); - /* enet, epit, gpt, spi */ - reg = CCGR1_ENET | CCGR1_EPIT1 | CCGR1_GPT | CCGR1_ECSPI1 | - CCGR1_ECSPI2 | CCGR1_ECSPI3 | CCGR1_ECSPI4 | CCGR1_ECSPI5; + if (soc == IMXSOC_6UL) + reg = 0xffffffff; + else + /* enet, epit, gpt, spi */ + reg = CCGR2_I2C1 | CCGR2_I2C2 | CCGR2_I2C3 | CCGR2_IIM | + CCGR2_IOMUX_IPT | CCGR2_IPMUX1 | CCGR2_IPMUX2 | CCGR2_IPMUX3 | + CCGR2_IPSYNC_IP2APB_TZASC1 | CCGR2_IPSYNC_IP2APB_TZASC2 | + CCGR2_IPSYNC_VDOA; WR4(sc, CCM_CCGR1, reg); - /* ipmux & ipsync (bridges), iomux, i2c */ - reg = CCGR2_I2C1 | CCGR2_I2C2 | CCGR2_I2C3 | CCGR2_IIM | - CCGR2_IOMUX_IPT | CCGR2_IPMUX1 | CCGR2_IPMUX2 | CCGR2_IPMUX3 | - CCGR2_IPSYNC_IP2APB_TZASC1 | CCGR2_IPSYNC_IP2APB_TZASC2 | - CCGR2_IPSYNC_VDOA; + if (soc == IMXSOC_6UL) + reg = 0xfc3fffff; + else + /* ipmux & ipsync (bridges), iomux, i2c */ + reg = CCGR2_I2C1 | CCGR2_I2C2 | CCGR2_I2C3 | CCGR2_IIM | + CCGR2_IOMUX_IPT | CCGR2_IPMUX1 | CCGR2_IPMUX2 | CCGR2_IPMUX3 | + CCGR2_IPSYNC_IP2APB_TZASC1 | CCGR2_IPSYNC_IP2APB_TZASC2 | + CCGR2_IPSYNC_VDOA; WR4(sc, CCM_CCGR2, reg); - /* DDR memory controller */ - reg = CCGR3_OCRAM | CCGR3_MMDC_CORE_IPG | - CCGR3_MMDC_CORE_ACLK_FAST | CCGR3_CG11 | CCGR3_CG13; + if (soc == IMXSOC_6UL) + reg = 0xffffffff; + else + /* DDR memory controller */ + reg = CCGR3_OCRAM | CCGR3_MMDC_CORE_IPG | + CCGR3_MMDC_CORE_ACLK_FAST | CCGR3_CG11 | CCGR3_CG13; WR4(sc, CCM_CCGR3, reg); - /* pl301 bus crossbar */ - reg = CCGR4_PL301_MX6QFAST1_S133 | - CCGR4_PL301_MX6QPER1_BCH | CCGR4_PL301_MX6QPER2_MAIN; + if (soc == IMXSOC_6UL) + reg = 0xffffffff; + else + /* pl301 bus crossbar */ + reg = CCGR4_PL301_MX6QFAST1_S133 | + CCGR4_PL301_MX6QPER1_BCH | CCGR4_PL301_MX6QPER2_MAIN; WR4(sc, CCM_CCGR4, reg); - /* uarts, ssi, sdma */ - reg = CCGR5_SDMA | CCGR5_SSI1 | CCGR5_SSI2 | CCGR5_SSI3 | - CCGR5_UART | CCGR5_UART_SERIAL; + if (soc == IMXSOC_6UL) + reg = 0xffffffff; + else + /* uarts, ssi, sdma */ + reg = CCGR5_SDMA | CCGR5_SSI1 | CCGR5_SSI2 | CCGR5_SSI3 | + CCGR5_UART | CCGR5_UART_SERIAL; WR4(sc, CCM_CCGR5, reg); - /* usdhc 1-4, usboh3 */ - reg = CCGR6_USBOH3 | CCGR6_USDHC1 | CCGR6_USDHC2 | - CCGR6_USDHC3 | CCGR6_USDHC4; + if (soc == IMXSOC_6UL) + reg = 0xffffffff; + else + /* usdhc 1-4, usboh3 */ + reg = CCGR6_USBOH3 | CCGR6_USDHC1 | CCGR6_USDHC2 | + CCGR6_USDHC3 | CCGR6_USDHC4; WR4(sc, CCM_CCGR6, reg); } @@ -202,8 +235,9 @@ if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0) - return (ENXIO); + if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0) + if (ofw_bus_is_compatible(dev, "fsl,imx6ul-ccm") == 0) + return (ENXIO); device_set_desc(dev, "Freescale i.MX6 Clock Control Module"); @@ -317,6 +351,67 @@ #endif } +int +imx6ul_ccm_enet_set50(void) +{ + return imx6ul_ccm_enet_enable(CCM_ANALOG_PLL_ENET0_DIV_SELECT_50); +} + +/* + * XXX This is really only for board designs that use the ENET_REF + * clock as a 50MHz output to drive the (presumably RMII) PHY. + * For MII or RGMII, something very different will need to happen. + */ +static int +imx6ul_ccm_enet_enable(uint32_t div) +{ + uint32_t v; + int timeout; + phandle_t gpr_node; + + gpr_node = ofw_bus_find_compatible(OF_finddevice("/"), "fsl,imx6ul-iomuxc-gpr"); + if (gpr_node) { + struct syscon *gpr; + + if (syscon_get_by_ofw_node(ccm_sc->dev, gpr_node, &gpr) == 0) { + SYSCON_MODIFY_4(gpr, IOMUXC_GPR1, IOMUXC_GPR1_ENET1_CLK_SEL, IOMUXC_GPR1_ENET1_TX_CLK_DIR); + } + } + + v = RD4(ccm_sc, CCM_ANALOG_PLL_ENET); + + /* Power up the PLL that feeds ENET phys. */ + if (v & CCM_ANALOG_PLL_ENET_POWERDOWN) { + v &= ~CCM_ANALOG_PLL_ENET_POWERDOWN; + WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v); + } + + /* Wait for lock. */ + if (!(v & CCM_ANALOG_PLL_ENET_LOCK)) { + for (timeout = 100000; timeout > 0; timeout--) { + if ((v = RD4(ccm_sc, CCM_ANALOG_PLL_ENET)) & + CCM_ANALOG_PLL_ENET_LOCK) { + break; + } + } + if (timeout <= 0) + return ETIMEDOUT; + } + + /* Enable the PLL */ + v |= CCM_ANALOG_PLL_ENET_ENABLE; + v &= ~CCM_ANALOG_PLL_ENET_BYPASS; + v &= ~(CCM_ANALOG_PLL_ENET0_DIV_MASK | CCM_ANALOG_PLL_ENET1_DIV_MASK); + v |= div; + WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v); + /* Set up as output to PHY */ + + /* Un-gate the enet controller. */ + WR4(ccm_sc, CCM_CCGR3, RD4(ccm_sc, CCM_CCGR3) | CCGR3_UL_ENET); + + return 0; +} + int imx6_ccm_sata_enable(void) { @@ -495,7 +590,6 @@ void imx_ccm_set_cacrr(uint32_t divisor) { - WR4(ccm_sc, CCM_CACCR, divisor); } diff --git a/sys/arm/freescale/imx/imx6_ccmreg.h b/sys/arm/freescale/imx/imx6_ccmreg.h --- a/sys/arm/freescale/imx/imx6_ccmreg.h +++ b/sys/arm/freescale/imx/imx6_ccmreg.h @@ -82,24 +82,34 @@ #define CCGR0_AIPS_TZ1 (0x3 << 0) #define CCGR0_AIPS_TZ2 (0x3 << 2) #define CCGR0_ABPHDMA (0x3 << 4) +#define CCGR0_UL_UART2 (0x3 << 28) #define CCM_CCGR1 0x06C #define CCGR1_ECSPI1 (0x3 << 0) #define CCGR1_ECSPI2 (0x3 << 2) #define CCGR1_ECSPI3 (0x3 << 4) #define CCGR1_ECSPI4 (0x3 << 6) +#define CCGR1_UL_ADC2 (0x3 << 8) #define CCGR1_ECSPI5 (0x3 << 8) +#define CCGR1_UL_UART3 (0x3 << 10) #define CCGR1_ENET (0x3 << 10) #define CCGR1_EPIT1 (0x3 << 12) #define CCGR1_EPIT2 (0x3 << 14) +#define CCGR1_UL_ADC1 (0x3 << 16) #define CCGR1_ESAI (0x3 << 16) +#define CCGR1_SIM_S (0x3 << 18) #define CCGR1_GPT (0x3 << 20) #define CCGR1_GPT_SERIAL (0x3 << 22) +#define CCGR1_UL_UART4 (0x3 << 24) +#define CCGR1_UL_GPIO1 (0x3 << 26) +#define CCGR1_UL_CSU (0x3 << 28) +#define CCGR1_UL_GPIO5 (0x3 << 30) #define CCM_CCGR2 0x070 #define CCGR2_HDMI_TX (0x3 << 0) #define CCGR2_HDMI_TX_ISFR (0x3 << 4) #define CCGR2_I2C1 (0x3 << 6) #define CCGR2_I2C2 (0x3 << 8) #define CCGR2_I2C3 (0x3 << 10) +#define CCGR2_UL_OCOTP (0x3 << 12) #define CCGR2_IIM (0x3 << 12) #define CCGR2_IOMUX_IPT (0x3 << 14) #define CCGR2_IPMUX1 (0x3 << 16) @@ -107,39 +117,62 @@ #define CCGR2_IPMUX3 (0x3 << 20) #define CCGR2_IPSYNC_IP2APB_TZASC1 (0x3 << 22) #define CCGR2_IPSYNC_IP2APB_TZASC2 (0x3 << 24) +#define CCGR2_UL_GPIO3 (0x3 << 26) #define CCGR2_IPSYNC_VDOA (0x3 << 26) #define CCM_CCGR3 0x074 +#define CCGR3_UL_CSI_MCLK (0x3 << 0) #define CCGR3_IPU1_IPU (0x3 << 0) +#define CCGR3_UL_UART5 (0x3 << 2) #define CCGR3_IPU1_DI0 (0x3 << 2) +#define CCGR3_UL_ENET (0x3 << 4) #define CCGR3_IPU1_DI1 (0x3 << 4) +#define CCGR3_UL_UART6 (0x3 << 6) #define CCGR3_IPU2_IPU (0x3 << 6) +#define CCGR3_UL_CA7_CCM_DAP (0x3 << 8) #define CCGR3_IPU2_DI0 (0x3 << 8) +#define CCGR3_UL_LCDIF1 (0x3 << 10) #define CCGR3_IPU2_DI1 (0x3 << 10) +#define CCGR3_UL_GPIO4 (0x3 << 12) #define CCGR3_LDB_DI0 (0x3 << 12) +#define CCGR3_UL_QSPI1 (0x3 << 14) #define CCGR3_LDB_DI1 (0x3 << 14) +#define CCGR3_UL_WDOG1 (0x3 << 16) #define CCGR3_MMDC_CORE_ACLK_FAST (0x3 << 20) #define CCGR3_CG11 (0x3 << 22) #define CCGR3_MMDC_CORE_IPG (0x3 << 24) #define CCGR3_CG13 (0x3 << 26) #define CCGR3_OCRAM (0x3 << 28) #define CCM_CCGR4 0x078 +#define CCGR4_UL_IOMUXC (0x3 << 2) +#define CCGR4_UL_IOMUXC_GPR (0x3 << 4) +#define CCGR4_UL_SIM_CPU (0x3 << 6) +#define CCGR4_UL_CXAPBSYNCBRIDGE_SLAVE (0x3 << 8) #define CCGR4_PL301_MX6QFAST1_S133 (0x3 << 8) +#define CCGR4_UL_TSC_DIG (0x3 << 10) #define CCGR4_PL301_MX6QPER1_BCH (0x3 << 12) #define CCGR4_PL301_MX6QPER2_MAIN (0x3 << 14) #define CCM_CCGR5 0x07C #define CCGR5_SATA (0x3 << 4) #define CCGR5_SDMA (0x3 << 6) +#define CCGR5_UL_WDOG2 (0x3 << 10) +#define CCGR5_UL_SIM_MAIN (0x3 << 16) #define CCGR5_SSI1 (0x3 << 18) #define CCGR5_SSI2 (0x3 << 20) #define CCGR5_SSI3 (0x3 << 22) +#define CCGR5_UL_UART1 (0x3 << 24) #define CCGR5_UART (0x3 << 24) +#define CCGR5_UL_UART7 (0x3 << 26) #define CCGR5_UART_SERIAL (0x3 << 26) #define CCM_CCGR6 0x080 #define CCGR6_USBOH3 (0x3 << 0) #define CCGR6_USDHC1 (0x3 << 2) #define CCGR6_USDHC2 (0x3 << 4) +#define CCGR6_UL_SIM1 (0x3 << 6) #define CCGR6_USDHC3 (0x3 << 6) +#define CCGR6_UL_SIM2 (0x3 << 8) #define CCGR6_USDHC4 (0x3 << 8) +#define CCGR6_UL_UART8 (0x3 << 14) +#define CCGR6_UL_WDOG3 (0x3 << 20) #define CCM_CMEOR 0x088 #define CCM_ANALOG_PLL_VIDEO 0x000040a0 @@ -157,9 +190,20 @@ #define CCM_ANALOG_PLL_ENET 0x000040e0 #define CCM_ANALOG_PLL_ENET_LOCK (1u << 31) +#define CCM_ANALOG_PLL_ENET25 (1u << 21) #define CCM_ANALOG_PLL_ENET_ENABLE_100M (1u << 20) /* SATA */ #define CCM_ANALOG_PLL_ENET_BYPASS (1u << 16) #define CCM_ANALOG_PLL_ENET_ENABLE (1u << 13) /* Ether */ #define CCM_ANALOG_PLL_ENET_POWERDOWN (1u << 12) +#define CCM_ANALOG_PLL_ENET1_DIV_SELECT_25 (0u << 2) +#define CCM_ANALOG_PLL_ENET1_DIV_SELECT_50 (1u << 2) +#define CCM_ANALOG_PLL_ENET1_DIV_SELECT_100 (2u << 2) +#define CCM_ANALOG_PLL_ENET1_DIV_SELECT_125 (3u << 2) +#define CCM_ANALOG_PLL_ENET1_DIV_MASK (3u << 2) +#define CCM_ANALOG_PLL_ENET0_DIV_SELECT_25 (0u) +#define CCM_ANALOG_PLL_ENET0_DIV_SELECT_50 (1u) +#define CCM_ANALOG_PLL_ENET0_DIV_SELECT_100 (2u) +#define CCM_ANALOG_PLL_ENET0_DIV_SELECT_125 (3u) +#define CCM_ANALOG_PLL_ENET0_DIV_MASK (3u) #endif diff --git a/sys/arm/freescale/imx/imx_ccmvar.h b/sys/arm/freescale/imx/imx_ccmvar.h --- a/sys/arm/freescale/imx/imx_ccmvar.h +++ b/sys/arm/freescale/imx/imx_ccmvar.h @@ -58,6 +58,7 @@ void imx_ccm_hdmi_enable(void); void imx_ccm_ipu_enable(int ipu); int imx6_ccm_sata_enable(void); +int imx6ul_ccm_enet_set50(void); /* Routines to get and set the arm clock root divisor register. */ uint32_t imx_ccm_get_cacrr(void); diff --git a/sys/arm/freescale/imx/imx_epit.c b/sys/arm/freescale/imx/imx_epit.c --- a/sys/arm/freescale/imx/imx_epit.c +++ b/sys/arm/freescale/imx/imx_epit.c @@ -374,7 +374,8 @@ bus_free_resource(dev, SYS_RES_MEMORY, memres); if (imx_soc_family() == 6) { - if (unit > 0) + // Having a second EPIT allows using it for kern.timecounter + if (unit > 1) return (ENXIO); if (ioaddr != imx6_epit_ioaddr[unit]) return (ENXIO); diff --git a/sys/arm/freescale/imx/imx_gpio.c b/sys/arm/freescale/imx/imx_gpio.c --- a/sys/arm/freescale/imx/imx_gpio.c +++ b/sys/arm/freescale/imx/imx_gpio.c @@ -134,6 +134,7 @@ static struct ofw_compat_data compat_data[] = { {"fsl,imx8mq-gpio", 1}, {"fsl,imx6q-gpio", 1}, + {"fsl,imx6ul-gpio", 1}, {"fsl,imx53-gpio", 1}, {"fsl,imx51-gpio", 1}, {NULL, 0} diff --git a/sys/arm/freescale/imx/imx_iomuxreg.h b/sys/arm/freescale/imx/imx_iomuxreg.h --- a/sys/arm/freescale/imx/imx_iomuxreg.h +++ b/sys/arm/freescale/imx/imx_iomuxreg.h @@ -38,6 +38,8 @@ #define IOMUXC_GPR0 0x00 #define IOMUXC_GPR1 0x04 +#define IOMUXC_GPR1_ENET1_CLK_SEL (1u << 13) +#define IOMUXC_GPR1_ENET1_TX_CLK_DIR (1u << 17) #define IOMUXC_GPR2 0x08 #define IOMUXC_GPR3 0x0C #define IOMUXC_GPR3_HDMI_MASK (3 << 2) diff --git a/sys/arm/freescale/vybrid/vf_adc.c b/sys/arm/freescale/vybrid/vf_adc.c --- a/sys/arm/freescale/vybrid/vf_adc.c +++ b/sys/arm/freescale/vybrid/vf_adc.c @@ -132,7 +132,8 @@ return (ENXIO); if (!ofw_bus_is_compatible(dev, "fsl,mvf600-adc")) - return (ENXIO); + if (!ofw_bus_is_compatible(dev, "fsl,vf610-adc")) + return (ENXIO); device_set_desc(dev, "Vybrid Family " "12-bit Analog to Digital Converter"); diff --git a/sys/contrib/device-tree/src/arm/sbc_ec9100.dts b/sys/contrib/device-tree/src/arm/sbc_ec9100.dts new file mode 100755 --- /dev/null +++ b/sys/contrib/device-tree/src/arm/sbc_ec9100.dts @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/dts-v1/; + +#include +#include "imx6ul.dtsi" + +/ { + model = "Embest SBC-EC9100 Board (i.MX6 UltraLite 14x14) "; + compatible = "fsl,embest_evk_ec9100", "fsl,imx6ul"; + + chosen { + stdout-path = "serial2:115200n8"; + }; + + memory { + reg = <0x80000000 0x20000000>; + }; + + regulators { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + }; + + leds { + compatible = "gpio-leds"; + + led1 { + label = "system_leds"; + gpios = <&gpio1 19 1>; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&cpu0 { + arm-supply = <®_arm>; + soc-supply = <®_soc>; + clock-frequency = <528000000>; +}; + +&clks { + assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <786432000>; +}; + +&gpc { + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; + dmas = <&sdma 29 4 0>, <&sdma 30 4 2>; + dma-names = "rx", "tx"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + cd-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + wp-disable; + keep-power-in-suspend; + enable-sdio-wakeup; + status = "okay"; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + phy-mode = "rmii"; + phy-handle = <ðphy0>; + status = "okay"; + // Deprecated + //phy-reset-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; + //phy-reset-duration = <1>; + //phy-reset-postdelay = <1>; + // This appears to be a FreeBSD extension. + //phy-disable-preamble; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + suppress-preamble; + + ethphy0: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + micrel,led-mode = <1>; + clocks = <&clks IMX6UL_CLK_ENET_REF>; + clock-names = "rmii-ref"; + max-speed = <100>; + interrupt-parent = <&gpio5>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; + reset-assert-us = <500>; + reset-deassert-us = <100>; + }; + }; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + status = "okay"; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + fsl,uart-has-rtscts; + cts-gpio = <&gpio1 18 0>; + status = "okay"; + linux,rs485-enabled-at-boot-time; + dmas = <&sdma 25 4 0>, <&sdma 26 4 2>; + dma-names = "rx", "tx"; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + no-1-8-v; + non-removable; + keep-power-in-suspend; + enable-sdio-wakeup; + bus-width = <8>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic: pfuze3000@8 { + compatible = "fsl,pfuze3001"; + reg = <0x08>; + fsl,pfuze-support-disable-sw; + + regulators { + // A7 part defaults to 1.4 + sw1a_reg: sw1a { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + // A7 part defaults to 1.4 + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + // A7 part defaults to 3.3 + sw2_reg: sw2 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + // A7 part defaults to 1.35 + sw3a_reg: sw3 { + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-boot-on; + regulator-always-on; + }; + + // TODO: Verify this... reset etc. + // It looks like this actually needs to be at least 3 + // A7 part defaults to 3.0 + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + // A7 part defaults to 3.3 + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + // Not connected in schematic + // A7 part defaults to 1.5 (OFF) + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + // Was 1V8, 3V3 on schematic + // A7 part defaults to 3.3/1.85 depending on strapping + vgen3_reg: vccsd { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + // A7 part defaults to 3.3 + vgen4_reg: v33 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + // Was 3V3, despite schematic, but has nothing on it. + // (Is for WiFi which is DNP) + // A7 part defaults to 1.8 (OFF) + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + // Nothing in schemtatic, but listed as 3V3 + // A7 part defaults to 1.8 + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + + // Serial EEPROM + at24@50 { + compatible = "at24,24c256"; + pagesize = <64>; + reg = <0x50>; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; + dmas = <&sdma 27 4 0>, <&sdma 28 4 2>; + dma-names = "rx", "tx"; +}; + +&usbotg1 { + dr_mode = "otg"; + disable-over-current; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + + +&usbotg2 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&adc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc1>; + status = "okay"; + vref-supply = <&vgen1_reg>; + adc-ch-list = <4>; +}; + +&aips2 { + adc2: adc@219c000 { + compatible = "fsl,imx6ul-adc", "fsl,vf610-adc"; + reg = <0x0219c000 0x4000>; + interrupts = ; + clocks = <&clks IMX6UL_CLK_ADC2>; + clock-names = "adc"; + fsl,adck-max-frequency = <30000000>, <40000000>, + <20000000>; + status = "disabled"; + }; +}; + +&adc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc2>; + status = "okay"; + vref-supply = <&vgen1_reg>; + adc-ch-list = <5>; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog_1>; + imx6ul-evk { + pinctrl_hog_1: hoggrp-1 { + fsl,pins = < + MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0 /*reset gpio*/ + MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00 0x80000000 /*cs-gpio*/ + MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x17059 /* GPIO EX */ + MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* GPIO/PWM2*/ + MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x80000000 /* LED */ + MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x80000000 + MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0 // tsc + >; + }; + + pinctrl_csi1: csi1grp { + fsl,pins = < + MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088 + MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088 + MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088 + MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088 + MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088 + MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088 + MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088 + MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088 + MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088 + MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088 + MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088 + MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0x1b0b1 + MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x17059 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x10071 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x17059 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x17059 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x17059 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x17059 + MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x17059 /* SD1 CD */ + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170b9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100b9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6UL_PAD_SD1_CMD__USDHC1_CMD 0x170f9 + MX6UL_PAD_SD1_CLK__USDHC1_CLK 0x100f9 + MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9 + MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9 + MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9 + MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9 + >; + }; + + pinctrl_enet1: enet1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO06__ENET1_MDIO 0xa8e8 + /* These were all 0x1b0b0 */ + MX6UL_PAD_GPIO1_IO07__ENET1_MDC 0xa0e9 + MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0 + MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0 + MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b010 + // Needs to have sion bit for Linux... 0x4001b031 + //MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x1b031 + MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031 + MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0 + MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0 + MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0 + MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0 + MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x80000000 /* PHY Reset (Active Low with pull-up) */ + >; + }; + + pinctrl_flexcan2: flexcan2grp{ + fsl,pins = < + MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX 0x1b020 + MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX 0x1b020 + >; + }; + + pinctrl_flexcan1: flexcan1grp{ + fsl,pins = < + MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020 + MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1 + MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1 + /* MX6UL_PAD_UART1_CTS_B__UART1_DCE_CTS 0x1b0b1*/ + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10069 + MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059 + MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059 + MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059 + MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059 + MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059 + MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x17059 + MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x17059 + MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x17059 + MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x17059 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO02__I2C1_SCL 0x4001b8b0 + MX6UL_PAD_GPIO1_IO03__I2C1_SDA 0x4001b8b0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1 + MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_lcdif_dat: lcdifdatgrp { + fsl,pins = < + MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 + MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 + MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 + MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 + MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 + MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 + MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 + MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 + MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 + MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 + MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 + MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 + MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 + MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 + MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 + MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 + MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 + MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 + MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79 + MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79 + MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79 + MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79 + MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79 + MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79 + >; + }; + + pinctrl_lcdif_ctrl: lcdifctrlgrp { + fsl,pins = < + MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 + MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 + MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 + MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 + >; + }; + + pinctrl_ecspi2_1: ecspi2grp-1 { + fsl,pins = < + MX6UL_PAD_UART5_TX_DATA__ECSPI2_MOSI 0x0b0b0 /* CSPI_MOSI */ + MX6UL_PAD_UART5_RX_DATA__ECSPI2_MISO 0x0b0b0 /* CSPI_MISO */ + MX6UL_PAD_UART4_TX_DATA__ECSPI2_SCLK 0x0b0b0 /* CSPI_SCLK */ + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 + >; + }; + + pinctrl_adc1: adc1grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0 + >; + }; + + pinctrl_adc2: adc2grp { + fsl,pins = < + MX6UL_PAD_GPIO1_IO05__GPIO1_IO05 0xb0 + >; + }; + }; +}; + +&snvs_poweroff { + status = "okay"; +}; + +&snvs_pwrkey { + status = "okay"; +}; + +&gpt2 { + status = "okay"; +}; diff --git a/sys/dev/cpufreq/cpufreq_dt.c b/sys/dev/cpufreq/cpufreq_dt.c --- a/sys/dev/cpufreq/cpufreq_dt.c +++ b/sys/dev/cpufreq/cpufreq_dt.c @@ -500,6 +500,11 @@ else if (regulator_get_by_ofw_property(dev, node, "cpu0-supply", &sc->reg) == 0) device_printf(dev, "Found cpu0-supply\n"); + else if (regulator_get_by_ofw_property(dev, node, "arm-supply", + &sc->reg) == 0) + device_printf(dev, "Found arm-supply\n"); + else + device_printf(dev, "No regulator found\n"); /* * Determine which operating mode we're in. Error out if we expect diff --git a/sys/dev/ffec/if_ffec.c b/sys/dev/ffec/if_ffec.c --- a/sys/dev/ffec/if_ffec.c +++ b/sys/dev/ffec/if_ffec.c @@ -89,6 +89,11 @@ #include #include "miibus_if.h" +#ifdef SOC_IMX6 +#include +#include +#endif + /* * There are small differences in the hardware on various SoCs. Not every SoC * we support has its own FECTYPE; most work as GENERIC and only the ones that @@ -363,6 +368,29 @@ return (0); } +static void +ffec_rcr_phy_flags(uint32_t *rcr, mii_contype_t t) +{ + switch (t) { + case MII_CONTYPE_MII: + *rcr |= FEC_RCR_MII_MODE; + break; + case MII_CONTYPE_RMII: + *rcr |= FEC_RCR_MII_MODE; /* Must always be on even for R[G]MII. */ + *rcr |= FEC_RCR_RMII_MODE; + break; + case MII_CONTYPE_RGMII: + case MII_CONTYPE_RGMII_ID: + case MII_CONTYPE_RGMII_RXID: + case MII_CONTYPE_RGMII_TXID: + *rcr |= FEC_RCR_MII_MODE; /* Must always be on even for R[G]MII. */ + *rcr |= FEC_RCR_RGMII_EN; + break; + default: + break; + } +} + static void ffec_miibus_statchg(device_t dev) { @@ -391,20 +419,7 @@ FEC_RCR_RGMII_EN | FEC_RCR_DRT | FEC_RCR_FCE); tcr = RD4(sc, FEC_TCR_REG) & ~FEC_TCR_FDEN; - rcr |= FEC_RCR_MII_MODE; /* Must always be on even for R[G]MII. */ - switch (sc->phy_conn_type) { - case MII_CONTYPE_RMII: - rcr |= FEC_RCR_RMII_MODE; - break; - case MII_CONTYPE_RGMII: - case MII_CONTYPE_RGMII_ID: - case MII_CONTYPE_RGMII_RXID: - case MII_CONTYPE_RGMII_TXID: - rcr |= FEC_RCR_RGMII_EN; - break; - default: - break; - } + ffec_rcr_phy_flags(&rcr, sc->phy_conn_type); switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_1000_T: @@ -420,6 +435,8 @@ case IFM_NONE: sc->link_is_up = false; return; + case IFM_AUTO: + break; default: sc->link_is_up = false; device_printf(dev, "Unsupported media %u\n", @@ -1154,7 +1171,9 @@ * * Set max frame length + clean out anything left from u-boot. */ - WR4(sc, FEC_RCR_REG, (maxfl << FEC_RCR_MAX_FL_SHIFT)); + regval = (maxfl << FEC_RCR_MAX_FL_SHIFT); + ffec_rcr_phy_flags(®val, sc->phy_conn_type); + WR4(sc, FEC_RCR_REG, regval); /* * TCR - Transmit control register. @@ -1471,8 +1490,10 @@ if_t ifp = NULL; struct mbuf *m; void *dummy; + char *name; uintptr_t typeflags; phandle_t ofw_node; + phandle_t mdio_node; uint32_t idx, mscr; int error, phynum, rid, irq; uint8_t eaddr[ETHER_ADDR_LEN]; @@ -1514,6 +1535,12 @@ error = ENOATTR; goto out; } +#ifdef SOC_IMX6 + /* Enable 50MHz ENET_REF output clock */ + if ((imx_soc_type() == IMXSOC_6UL) && + sc->phy_conn_type == MII_CONTYPE_RMII) + imx6ul_ccm_enet_set50(); +#endif callout_init_mtx(&sc->ffec_callout, &sc->mtx, 0); @@ -1734,6 +1761,30 @@ if (bootverbose) device_printf(dev, "PHY preamble disabled\n"); } + /* + * Now look for the documented mdio.suppress-preamble... + * this is allowed to be named mdio@ + */ + for (mdio_node = OF_child(ofw_node); mdio_node != 0; mdio_node = OF_peer(mdio_node)) { + if (OF_getprop_alloc(mdio_node, "name", (void **)&name) != -1) { + if (strcmp(name, "mdio") == 0) { + free(name, M_OFWPROP); + break; + } + if (strncmp(name, "mdio@", 5) == 0) { + free(name, M_OFWPROP); + break; + } + free(name, M_OFWPROP); + } + } + if (mdio_node != 0) { + if (OF_hasprop(mdio_node, "suppress-preamble")) { + mscr |= FEC_MSCR_DIS_PRE; + if (bootverbose) + device_printf(dev, "PHY preamble disabled\n"); + } + } WR4(sc, FEC_MSCR_REG, mscr); /* Set up the ethernet interface. */ @@ -1759,6 +1810,11 @@ /* Set up the miigasket hardware (if any). */ ffec_miigasket_setup(sc); + /* RCR - Receive control register. */ + uint32_t regval = RD4(sc, FEC_RCR_REG); + ffec_rcr_phy_flags(®val, sc->phy_conn_type); + WR4(sc, FEC_RCR_REG, regval); + /* Attach the mii driver. */ if (fdt_get_phyaddr(ofw_node, dev, &phynum, &dummy) != 0) { phynum = MII_PHY_ANY; diff --git a/sys/dev/mii/micphy.c b/sys/dev/mii/micphy.c --- a/sys/dev/mii/micphy.c +++ b/sys/dev/mii/micphy.c @@ -60,6 +60,7 @@ #include #include #include +#include #define MII_KSZPHY_EXTREG 0x0b #define KSZPHY_EXTREG_WRITE (1 << 15) @@ -78,9 +79,20 @@ #define MII_KSZ9031_CLOCK_PAD_SKEW 0x8 #define MII_KSZ8081_PHYCTL2 0x1f +#define MII_KSZ8081_PHYCTL2_LED_SHIFT 4 +#define MII_KSZ8081_PHYCTL2_LED_MASK (3 << MII_KSZ8081_PHYCTL2_LED_SHIFT) +#define MII_KSZ8081_PHYCTL2_50MHZ_RMII (1 << 7) #define PS_TO_REG(p) ((p) / 200) +struct micphy_softc { + struct mii_softc mii_softc; + mii_fdt_phy_config_t *cfg; + device_t dev; + uint16_t ctrl2_set_bits; + uint16_t ctrl2_clr_bits; +}; + static int micphy_probe(device_t); static int micphy_attach(device_t); static void micphy_reset(struct mii_softc *); @@ -98,7 +110,7 @@ static driver_t micphy_driver = { "micphy", micphy_methods, - sizeof(struct mii_softc) + sizeof(struct micphy_softc) }; DRIVER_MODULE(micphy, miibus, micphy_driver, 0, 0); @@ -247,36 +259,69 @@ return (mii_phy_dev_probe(dev, micphys, BUS_PROBE_DEFAULT)); } +static void +micphy_get_ctrl2_bits(struct micphy_softc *msc) +{ + pcell_t val; + + msc->ctrl2_set_bits = 0; + msc->ctrl2_clr_bits = 0; + + if (msc->cfg) { + if (msc->cfg->phynode != -1) { + if (OF_getencprop(msc->cfg->phynode, "micrel,led-mode", &val, sizeof(val)) > 0) { + msc->ctrl2_set_bits |= (val << MII_KSZ8081_PHYCTL2_LED_SHIFT) & + MII_KSZ8081_PHYCTL2_LED_MASK; + msc->ctrl2_clr_bits |= MII_KSZ8081_PHYCTL2_LED_MASK; + } + } + /* + * Assume a 50MHz clock for RMII, for everything else, + * assume the defaults are fine, or the bootloader set + * them up properly. + */ + if (msc->cfg->con_type == MII_CONTYPE_RMII) { + msc->ctrl2_set_bits |= MII_KSZ8081_PHYCTL2_50MHZ_RMII; + } + } +} + static int micphy_attach(device_t dev) { - mii_fdt_phy_config_t *cfg; + struct micphy_softc *msc; struct mii_softc *sc; phandle_t node; device_t miibus; device_t parent; - sc = device_get_softc(dev); + msc = device_get_softc(dev); + sc = &msc->mii_softc; + msc->dev = dev; mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &micphy_funcs, 1); mii_phy_setmedia(sc); - /* Nothing further to configure for 8081 model. */ - if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081) - return (0); - miibus = device_get_parent(dev); parent = device_get_parent(miibus); if ((node = ofw_bus_get_node(parent)) == -1) return (ENXIO); - cfg = mii_fdt_get_config(dev); + msc->cfg = mii_fdt_get_config(dev); + micphy_get_ctrl2_bits(msc); + + if (msc->cfg && msc->cfg->reset_gpio) + micphy_reset(sc); + + /* Nothing further to configure for 8081 model. */ + if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081) + return (0); if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9031) - ksz9031_load_values(sc, cfg->phynode); + ksz9031_load_values(sc, msc->cfg->phynode); else - ksz9021_load_values(sc, cfg->phynode); + ksz9021_load_values(sc, msc->cfg->phynode); return (0); } @@ -285,6 +330,8 @@ micphy_reset(struct mii_softc *sc) { int reg; + int rc; + struct micphy_softc *msc = (struct micphy_softc *)sc; /* * The 8081 has no "sticky bits" that survive a soft reset; several bits @@ -292,11 +339,32 @@ * These bits are set up by the bootloader; they control how the phy * interfaces to the board (such as clock frequency and LED behavior). */ - if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081) + if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081) { reg = PHY_READ(sc, MII_KSZ8081_PHYCTL2); - mii_phy_reset(sc); - if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081) + if (reg == 0xffff) + reg = 0x8100; + } + if (msc->cfg && msc->cfg->reset_gpio) { + rc = gpio_pin_set_active(msc->cfg->reset_gpio, true); + if (rc) { + device_printf(msc->dev, "Failed to set reset pin active: %d\n", rc); + } + DELAY(msc->cfg->reset_assert_us); + if (rc == 0 && gpio_pin_set_active(msc->cfg->reset_gpio, false)) { + device_printf(msc->dev, "Failed to set reset pin inactive: %d\n", rc); + } + DELAY(msc->cfg->reset_deassert_us); + } + else + { + mii_phy_reset(sc); + } + + if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081) { + reg &= ~msc->ctrl2_clr_bits; + reg |= msc->ctrl2_set_bits; PHY_WRITE(sc, MII_KSZ8081_PHYCTL2, reg); + } } static int diff --git a/sys/dev/mii/mii_fdt.h b/sys/dev/mii/mii_fdt.h --- a/sys/dev/mii/mii_fdt.h +++ b/sys/dev/mii/mii_fdt.h @@ -42,6 +42,9 @@ mii_contype_t con_type; /* MAC<->PHY connection type */ u_int max_speed; /* Mbits/sec, 0 = not specified */ uint32_t flags; /* MIIF_FDT_xxx boolean properties */ + struct gpiobus_pin *reset_gpio; + uint32_t reset_assert_us; + uint32_t reset_deassert_us; }; typedef struct mii_fdt_phy_config mii_fdt_phy_config_t; diff --git a/sys/dev/mii/mii_fdt.c b/sys/dev/mii/mii_fdt.c --- a/sys/dev/mii/mii_fdt.c +++ b/sys/dev/mii/mii_fdt.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include @@ -176,7 +178,10 @@ void mii_fdt_free_config(struct mii_fdt_phy_config *cfg) { - + if (cfg->reset_gpio) { + gpiobus_release_pin(GPIO_GET_BUS(cfg->reset_gpio->dev), cfg->reset_gpio->pin); + free(cfg->reset_gpio, M_DEVBUF); + } free(cfg, M_OFWPROP); } @@ -187,6 +192,7 @@ mii_fdt_phy_config_t *cfg; device_t miibus, macdev; pcell_t val; + int rc; ma = device_get_ivars(phydev); miibus = device_get_parent(phydev); @@ -202,6 +208,21 @@ return (cfg); cfg->con_type = mii_fdt_get_contype(cfg->macnode); + if (OF_hasprop(cfg->macnode, "phy-reset-gpios")) { + rc = gpio_pin_get_by_ofw_property(phydev, cfg->macnode, "phy-reset-gpios", + &cfg->reset_gpio); + if (rc == 0) { + gpio_pin_setflags(cfg->reset_gpio, GPIO_PIN_OUTPUT); + gpio_pin_set_active(cfg->reset_gpio, true); + if (OF_getencprop(cfg->phynode, "phy-reset-duration", &val, sizeof(val)) > 0) + cfg->reset_assert_us = val * 1000; + else { + cfg->reset_assert_us = 1000; + } + if (OF_getencprop(cfg->phynode, "phy-reset-postdelay", &val, sizeof(val)) > 0) + cfg->reset_assert_us = val * 1000; + } + } /* * If we can't find our own PHY node, there's nothing more we can fill @@ -236,6 +257,23 @@ cfg->flags |= MIIF_FDT_EEE_BROKEN_10GKX4; if (OF_hasprop(cfg->phynode, "eee-broken-10gkr")) cfg->flags |= MIIF_FDT_EEE_BROKEN_10GKR; + if (OF_hasprop(cfg->phynode, "reset-gpios")) { + if (cfg->reset_gpio) { + gpiobus_release_pin(GPIO_GET_BUS(cfg->reset_gpio->dev), cfg->reset_gpio->pin); + free(cfg->reset_gpio, M_DEVBUF); + cfg->reset_gpio = NULL; + } + rc = gpio_pin_get_by_ofw_property(phydev, cfg->phynode, "reset-gpios", + &cfg->reset_gpio); + if (rc == 0) { + gpio_pin_setflags(cfg->reset_gpio, GPIO_PIN_OUTPUT); + gpio_pin_set_active(cfg->reset_gpio, true); + if (OF_getencprop(cfg->phynode, "reset-assert-us", &val, sizeof(val)) > 0) + cfg->reset_assert_us = val; + if (OF_getencprop(cfg->phynode, "reset-deassert-us", &val, sizeof(val)) > 0) + cfg->reset_deassert_us = val; + } + } return (cfg); } diff --git a/sys/dev/sdhci/fsl_sdhci.c b/sys/dev/sdhci/fsl_sdhci.c --- a/sys/dev/sdhci/fsl_sdhci.c +++ b/sys/dev/sdhci/fsl_sdhci.c @@ -178,6 +178,7 @@ static struct ofw_compat_data compat_data[] = { {"fsl,imx6q-usdhc", HWTYPE_USDHC}, {"fsl,imx6sl-usdhc", HWTYPE_USDHC}, + {"fsl,imx6ul-usdhc", HWTYPE_USDHC}, {"fsl,imx53-esdhc", HWTYPE_ESDHC}, {"fsl,imx51-esdhc", HWTYPE_ESDHC}, {"fsl,esdhc", HWTYPE_ESDHC}, diff --git a/sys/modules/dtb/imx6/Makefile b/sys/modules/dtb/imx6/Makefile --- a/sys/modules/dtb/imx6/Makefile +++ b/sys/modules/dtb/imx6/Makefile @@ -15,5 +15,6 @@ imx6dl-wandboard-revb1.dts \ imx6q-wandboard.dts \ imx6q-wandboard-revb1.dts \ + sbc_ec9100.dts \ .include