From 595a67c0fcaa58c24fea13d595ed540c01d64e3c Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Wed, 17 Feb 2016 11:56:58 +0100 Subject: ARM: i.MX25: Add some more clocks Add some clocks needed for: - RNGB - SCC - Dryice RTC Signed-off-by: Steffen Trumtrar Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/include/mach/imx25-regs.h | 2 ++ drivers/clk/imx/clk-imx25.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/include/mach/imx25-regs.h b/arch/arm/mach-imx/include/mach/imx25-regs.h index 71812764c9..5974897a16 100644 --- a/arch/arm/mach-imx/include/mach/imx25-regs.h +++ b/arch/arm/mach-imx/include/mach/imx25-regs.h @@ -62,12 +62,14 @@ #define MX25_SSI2_BASE_ADDR 0x50014000 #define MX25_SSI1_BASE_ADDR 0x50034000 #define MX25_NFC_BASE_ADDR 0xbb000000 +#define MX25_SCC_BASE_ADDR 0x53fac000 #define MX25_IIM_BASE_ADDR 0x53ff0000 #define MX25_DRYICE_BASE_ADDR 0x53ffc000 #define MX25_ESDHC1_BASE_ADDR 0x53fb4000 #define MX25_ESDHC2_BASE_ADDR 0x53fb8000 #define MX25_LCDC_BASE_ADDR 0x53fbc000 #define MX25_KPP_BASE_ADDR 0x43fa8000 +#define MX25_RNGB_BASE_ADDR 0x53fb0000 #define MX25_SDMA_BASE_ADDR 0x53fd4000 #define MX25_USB_BASE_ADDR 0x53ff4000 #define MX25_USB_OTG_BASE_ADDR (MX25_USB_BASE_ADDR + 0x0000) diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c index baa42e14f4..ce4fbed68c 100644 --- a/drivers/clk/imx/clk-imx25.c +++ b/drivers/clk/imx/clk-imx25.c @@ -95,7 +95,7 @@ static int imx25_ccm_probe(struct device_d *dev) writel((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 15) | (1 << 19) | (1 << 21) | (1 << 22) | - (1 << 23) | (1 << 24) | (1 << 28), + (1 << 23) | (1 << 24) | (1 << 25) | (1 << 28), base + CCM_CGCR0); writel((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 13) | (1 << 14) | @@ -152,7 +152,9 @@ static int imx25_ccm_probe(struct device_d *dev) clks[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", base + CCM_CGCR0, 24); clks[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", base + CCM_CGCR1, 29); clks[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", base + CCM_CGCR0, 7); + clks[scc_ipg] = imx_clk_gate("scc_ipg", "ipg", base + CCM_CGCR2, 5); clks[rngb_ipg] = imx_clk_gate("rngb_ipg", "ipg", base + CCM_CGCR2, 3); + clks[dryice_ipg] = imx_clk_gate("dryice_ipg", "ipg", base + CCM_CGCR1, 8); clkdev_add_physbase(clks[per15], MX25_UART1_BASE_ADDR, NULL); clkdev_add_physbase(clks[per15], MX25_UART2_BASE_ADDR, NULL); @@ -176,6 +178,9 @@ static int imx25_ccm_probe(struct device_d *dev) clkdev_add_physbase(clks[lcdc_ipg_per], MX25_LCDC_BASE_ADDR, "per"); clkdev_add_physbase(clks[lcdc_ipg], MX25_LCDC_BASE_ADDR, "ipg"); clkdev_add_physbase(clks[lcdc_ahb], MX25_LCDC_BASE_ADDR, "ahb"); + clkdev_add_physbase(clks[scc_ipg], MX25_SCC_BASE_ADDR, "ipg"); + clkdev_add_physbase(clks[rngb_ipg], MX25_RNGB_BASE_ADDR, "ipg"); + clkdev_add_physbase(clks[dryice_ipg], MX25_DRYICE_BASE_ADDR, NULL); return 0; } -- cgit v1.2.3 From 595d4dbb6af4927478763bf1b2b8254e6b5dd7aa Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 11 Apr 2019 14:45:00 +0200 Subject: Add i.MX25 rtc driver This adds a RTC driver for the Freescale i.MX25. This is done more to get access to the nonvolatile general purpose register than it is done to read the clock. Signed-off-by: Sascha Hauer --- drivers/rtc/Kconfig | 6 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-imxdi.c | 623 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 630 insertions(+) create mode 100644 drivers/rtc/rtc-imxdi.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7d181949ee..9d2c6e614b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -38,6 +38,12 @@ config RTC_DRV_ABRACON endif # I2C +config RTC_DRV_IMXDI + tristate "Freescale IMX DryIce Real Time Clock" + depends on ARCH_IMX + help + Support for Freescale IMX DryIce RTC + config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 RTC" depends on MACH_MIPS_XBURST diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 68741c26a1..1308beff38 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_RTC_CLASS) += class.o obj-$(CONFIG_RTC_DRV_ABRACON) += rtc-abracon.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o +obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c new file mode 100644 index 0000000000..8fcaf631ff --- /dev/null +++ b/drivers/rtc/rtc-imxdi.c @@ -0,0 +1,623 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2010 Orex Computed Radiography + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* based on rtc-mc13892.c */ + +/* + * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block + * to implement a Linux RTC. Times and alarms are truncated to seconds. + * Since the RTC framework performs API locking via rtc->ops_lock the + * only simultaneous accesses we need to deal with is updating DryIce + * registers while servicing an alarm. + * + * Note that reading the DSR (DryIce Status Register) automatically clears + * the WCF (Write Complete Flag). All DryIce writes are synchronized to the + * LP (Low Power) domain and set the WCF upon completion. Writes to the + * DIER (DryIce Interrupt Enable Register) are the only exception. These + * occur at normal bus speeds and do not set WCF. Periodic interrupts are + * not supported by the hardware. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* DryIce Register Definitions */ + +#define DTCMR 0x00 /* Time Counter MSB Reg */ +#define DTCLR 0x04 /* Time Counter LSB Reg */ + +#define DCAMR 0x08 /* Clock Alarm MSB Reg */ +#define DCALR 0x0c /* Clock Alarm LSB Reg */ +#define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */ + +#define DCR 0x10 /* Control Reg */ +#define DCR_TDCHL (1 << 30) /* Tamper-detect configuration hard lock */ +#define DCR_TDCSL (1 << 29) /* Tamper-detect configuration soft lock */ +#define DCR_KSSL (1 << 27) /* Key-select soft lock */ +#define DCR_MCHL (1 << 20) /* Monotonic-counter hard lock */ +#define DCR_MCSL (1 << 19) /* Monotonic-counter soft lock */ +#define DCR_TCHL (1 << 18) /* Timer-counter hard lock */ +#define DCR_TCSL (1 << 17) /* Timer-counter soft lock */ +#define DCR_FSHL (1 << 16) /* Failure state hard lock */ +#define DCR_TCE (1 << 3) /* Time Counter Enable */ +#define DCR_MCE (1 << 2) /* Monotonic Counter Enable */ + +#define DSR 0x14 /* Status Reg */ +#define DSR_WTD (1 << 23) /* Wire-mesh tamper detected */ +#define DSR_ETBD (1 << 22) /* External tamper B detected */ +#define DSR_ETAD (1 << 21) /* External tamper A detected */ +#define DSR_EBD (1 << 20) /* External boot detected */ +#define DSR_SAD (1 << 19) /* SCC alarm detected */ +#define DSR_TTD (1 << 18) /* Temperature tamper detected */ +#define DSR_CTD (1 << 17) /* Clock tamper detected */ +#define DSR_VTD (1 << 16) /* Voltage tamper detected */ +#define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */ +#define DSR_WNF (1 << 9) /* Write Next Flag (synchronous) */ +#define DSR_WCF (1 << 8) /* Write Complete Flag (synchronous)*/ +#define DSR_WEF (1 << 7) /* Write Error Flag */ +#define DSR_CAF (1 << 4) /* Clock Alarm Flag */ +#define DSR_MCO (1 << 3) /* monotonic counter overflow */ +#define DSR_TCO (1 << 2) /* time counter overflow */ +#define DSR_NVF (1 << 1) /* Non-Valid Flag */ +#define DSR_SVF (1 << 0) /* Security Violation Flag */ + +#define DIER 0x18 /* Interrupt Enable Reg (synchronous) */ +#define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */ +#define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */ +#define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */ +#define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */ +#define DIER_SVIE (1 << 0) /* Security-violation Interrupt Enable */ + +#define DMCR 0x1c /* DryIce Monotonic Counter Reg */ + +#define DTCR 0x28 /* DryIce Tamper Configuration Reg */ +#define DTCR_MOE (1 << 9) /* monotonic overflow enabled */ +#define DTCR_TOE (1 << 8) /* time overflow enabled */ +#define DTCR_WTE (1 << 7) /* wire-mesh tamper enabled */ +#define DTCR_ETBE (1 << 6) /* external B tamper enabled */ +#define DTCR_ETAE (1 << 5) /* external A tamper enabled */ +#define DTCR_EBE (1 << 4) /* external boot tamper enabled */ +#define DTCR_SAIE (1 << 3) /* SCC enabled */ +#define DTCR_TTE (1 << 2) /* temperature tamper enabled */ +#define DTCR_CTE (1 << 1) /* clock tamper enabled */ +#define DTCR_VTE (1 << 0) /* voltage tamper enabled */ + +#define DGPR 0x3c /* DryIce General Purpose Reg */ + +/** + * struct imxdi_dev - private imxdi rtc data + * @dev: pionter to dev + * @rtc: pointer to rtc struct + * @ioaddr: IO registers pointer + * @clk: input reference clock + * @dsr: copy of the DSR register + */ +struct imxdi_dev { + struct device_d *dev; + struct rtc_device rtc; + void __iomem *ioaddr; + struct clk *clk; + u32 dsr; + struct nvmem_device *nvmem; +}; + +/* Some background: + * + * The DryIce unit is a complex security/tamper monitor device. To be able do + * its job in a useful manner it runs a bigger statemachine to bring it into + * security/tamper failure state and once again to bring it out of this state. + * + * This unit can be in one of three states: + * + * - "NON-VALID STATE" + * always after the battery power was removed + * - "FAILURE STATE" + * if one of the enabled security events has happened + * - "VALID STATE" + * if the unit works as expected + * + * Everything stops when the unit enters the failure state including the RTC + * counter (to be able to detect the time the security event happened). + * + * The following events (when enabled) let the DryIce unit enter the failure + * state: + * + * - wire-mesh-tamper detect + * - external tamper B detect + * - external tamper A detect + * - temperature tamper detect + * - clock tamper detect + * - voltage tamper detect + * - RTC counter overflow + * - monotonic counter overflow + * - external boot + * + * If we find the DryIce unit in "FAILURE STATE" and the TDCHL cleared, we + * can only detect this state. In this case the unit is completely locked and + * must force a second "SYSTEM POR" to bring the DryIce into the + * "NON-VALID STATE" + "FAILURE STATE" where a recovery is possible. + * If the TDCHL is set in the "FAILURE STATE" we are out of luck. In this case + * a battery power cycle is required. + * + * In the "NON-VALID STATE" + "FAILURE STATE" we can clear the "FAILURE STATE" + * and recover the DryIce unit. By clearing the "NON-VALID STATE" as the last + * task, we bring back this unit into life. + */ + +/* + * Do a write into the unit without interrupt support. + * We do not need to check the WEF here, because the only reason this kind of + * write error can happen is if we write to the unit twice within the 122 us + * interval. This cannot happen, since we are using this function only while + * setting up the unit. + */ +static void di_write_busy_wait(const struct imxdi_dev *imxdi, u32 val, + unsigned reg) +{ + /* do the register write */ + writel(val, imxdi->ioaddr + reg); + + /* + * now it takes four 32,768 kHz clock cycles to take + * the change into effect = 122 us + */ + udelay(130); +} + +static void di_what_is_to_be_done(struct imxdi_dev *imxdi, + const char *power_supply) +{ + dev_emerg(imxdi->dev, "Please cycle the %s power supply in order to get the DryIce/RTC unit working again\n", + power_supply); +} + +static int di_handle_failure_state(struct imxdi_dev *imxdi, u32 dsr) +{ + u32 dcr; + + dev_dbg(imxdi->dev, "DSR register reports: %08X\n", dsr); + + dcr = readl(imxdi->ioaddr + DCR); + + if (dcr & DCR_FSHL) { + /* we are out of luck */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + /* + * with the next SYSTEM POR we will transit from the "FAILURE STATE" + * into the "NON-VALID STATE" + "FAILURE STATE" + */ + di_what_is_to_be_done(imxdi, "main"); + + return -ENODEV; +} + +static int di_handle_valid_state(struct imxdi_dev *imxdi, u32 dsr) +{ + /* initialize alarm */ + di_write_busy_wait(imxdi, DCAMR_UNSET, DCAMR); + di_write_busy_wait(imxdi, 0, DCALR); + + /* clear alarm flag */ + if (dsr & DSR_CAF) + di_write_busy_wait(imxdi, DSR_CAF, DSR); + + return 0; +} + +static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr) +{ + u32 dcr, sec; + + /* + * lets disable all sources which can force the DryIce unit into + * the "FAILURE STATE" for now + */ + di_write_busy_wait(imxdi, 0x00000000, DTCR); + /* and lets protect them at runtime from any change */ + di_write_busy_wait(imxdi, DCR_TDCSL, DCR); + + sec = readl(imxdi->ioaddr + DTCMR); + if (sec != 0) + dev_warn(imxdi->dev, + "The security violation has happened at %u seconds\n", + sec); + /* + * the timer cannot be set/modified if + * - the TCHL or TCSL bit is set in DCR + */ + dcr = readl(imxdi->ioaddr + DCR); + if (!(dcr & DCR_TCE)) { + if (dcr & DCR_TCHL) { + /* we are out of luck */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + if (dcr & DCR_TCSL) { + di_what_is_to_be_done(imxdi, "main"); + return -ENODEV; + } + } + /* + * - the timer counter stops/is stopped if + * - its overflow flag is set (TCO in DSR) + * -> clear overflow bit to make it count again + * - NVF is set in DSR + * -> clear non-valid bit to make it count again + * - its TCE (DCR) is cleared + * -> set TCE to make it count + * - it was never set before + * -> write a time into it (required again if the NVF was set) + */ + /* state handled */ + di_write_busy_wait(imxdi, DSR_NVF, DSR); + /* clear overflow flag */ + di_write_busy_wait(imxdi, DSR_TCO, DSR); + /* enable the counter */ + di_write_busy_wait(imxdi, dcr | DCR_TCE, DCR); + /* set and trigger it to make it count */ + di_write_busy_wait(imxdi, sec, DTCMR); + + /* now prepare for the valid state */ + return di_handle_valid_state(imxdi, __raw_readl(imxdi->ioaddr + DSR)); +} + +static int di_handle_invalid_and_failure_state(struct imxdi_dev *imxdi, u32 dsr) +{ + u32 dcr; + + /* + * now we must first remove the tamper sources in order to get the + * device out of the "FAILURE STATE" + * To disable any of the following sources we need to modify the DTCR + */ + if (dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD | DSR_EBD | DSR_SAD | + DSR_TTD | DSR_CTD | DSR_VTD | DSR_MCO | DSR_TCO)) { + dcr = __raw_readl(imxdi->ioaddr + DCR); + if (dcr & DCR_TDCHL) { + /* + * the tamper register is locked. We cannot disable the + * tamper detection. The TDCHL can only be reset by a + * DRYICE POR, but we cannot force a DRYICE POR in + * softwere because we are still in "FAILURE STATE". + * We need a DRYICE POR via battery power cycling.... + */ + /* + * out of luck! + * we cannot disable them without a DRYICE POR + */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + if (dcr & DCR_TDCSL) { + /* a soft lock can be removed by a SYSTEM POR */ + di_what_is_to_be_done(imxdi, "main"); + return -ENODEV; + } + } + + /* disable all sources */ + di_write_busy_wait(imxdi, 0x00000000, DTCR); + + /* clear the status bits now */ + di_write_busy_wait(imxdi, dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD | + DSR_EBD | DSR_SAD | DSR_TTD | DSR_CTD | DSR_VTD | + DSR_MCO | DSR_TCO), DSR); + + dsr = readl(imxdi->ioaddr + DSR); + if ((dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF | + DSR_WCF | DSR_WEF)) != 0) + dev_warn(imxdi->dev, + "There are still some sources of pain in DSR: %08x!\n", + dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF | + DSR_WCF | DSR_WEF)); + + /* + * now we are trying to clear the "Security-violation flag" to + * get the DryIce out of this state + */ + di_write_busy_wait(imxdi, DSR_SVF, DSR); + + /* success? */ + dsr = readl(imxdi->ioaddr + DSR); + if (dsr & DSR_SVF) { + dev_crit(imxdi->dev, + "Cannot clear the security violation flag. We are ending up in an endless loop!\n"); + /* last resort */ + di_what_is_to_be_done(imxdi, "battery"); + return -ENODEV; + } + + /* + * now we have left the "FAILURE STATE" and ending up in the + * "NON-VALID STATE" time to recover everything + */ + return di_handle_invalid_state(imxdi, dsr); +} + +static int di_handle_state(struct imxdi_dev *imxdi) +{ + int rc; + u32 dsr; + + dsr = readl(imxdi->ioaddr + DSR); + + switch (dsr & (DSR_NVF | DSR_SVF)) { + case DSR_NVF: + dev_warn(imxdi->dev, "Invalid stated unit detected\n"); + rc = di_handle_invalid_state(imxdi, dsr); + break; + case DSR_SVF: + dev_warn(imxdi->dev, "Failure stated unit detected\n"); + rc = di_handle_failure_state(imxdi, dsr); + break; + case DSR_NVF | DSR_SVF: + dev_warn(imxdi->dev, + "Failure+Invalid stated unit detected\n"); + rc = di_handle_invalid_and_failure_state(imxdi, dsr); + break; + default: + dev_notice(imxdi->dev, "Unlocked unit detected\n"); + rc = di_handle_valid_state(imxdi, dsr); + } + + return rc; +} + +/* + * This function attempts to clear the dryice write-error flag. + * + * A dryice write error is similar to a bus fault and should not occur in + * normal operation. Clearing the flag requires another write, so the root + * cause of the problem may need to be fixed before the flag can be cleared. + */ +static void clear_write_error(struct imxdi_dev *imxdi) +{ + int cnt; + + dev_warn(imxdi->dev, "WARNING: Register write error!\n"); + + /* clear the write error flag */ + writel(DSR_WEF, imxdi->ioaddr + DSR); + + /* wait for it to take effect */ + for (cnt = 0; cnt < 1000; cnt++) { + if ((readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0) + return; + udelay(10); + } + dev_err(imxdi->dev, + "ERROR: Cannot clear write-error flag!\n"); +} + +/* + * Write a dryice register and wait until it completes. + * + * This function uses interrupts to determine when the + * write has completed. + */ +static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg) +{ + int rc = 0; + uint32_t dsr; + uint64_t start; + + /* do the register write */ + writel(val, imxdi->ioaddr + reg); + + start = get_time_ns(); + + /* wait for the write to finish */ + while (1) { + dsr = readl(imxdi->ioaddr + DSR); + + if (dsr & (DSR_WCF | DSR_WEF)) + break; + if (is_timeout(start, MSECOND)) + return -EIO; + } + + /* check for write error */ + if (dsr & DSR_WEF) { + clear_write_error(imxdi); + rc = -EIO; + } + + return rc; +} + +static struct imxdi_dev *to_imxdi_dev(struct rtc_device *rtc) +{ + return container_of(rtc, struct imxdi_dev, rtc); +} + +/* + * read the seconds portion of the current time from the dryice time counter + */ +static int dryice_rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + struct imxdi_dev *imxdi = to_imxdi_dev(rtc); + unsigned long now; + + now = readl(imxdi->ioaddr + DTCMR); + rtc_time_to_tm(now, tm); + + return 0; +} + +/* + * set the seconds portion of dryice time counter and clear the + * fractional part. + */ +static int dryice_rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + struct imxdi_dev *imxdi = to_imxdi_dev(rtc); + u32 dcr, dsr; + int ret; + unsigned long secs; + + ret = rtc_tm_to_time(tm, &secs); + if (ret) + return ret; + + dcr = readl(imxdi->ioaddr + DCR); + dsr = readl(imxdi->ioaddr + DSR); + + if (!(dcr & DCR_TCE) || (dsr & DSR_SVF)) { + if (dcr & DCR_TCHL) { + /* we are even more out of luck */ + di_what_is_to_be_done(imxdi, "battery"); + return -EPERM; + } + if ((dcr & DCR_TCSL) || (dsr & DSR_SVF)) { + /* we are out of luck for now */ + di_what_is_to_be_done(imxdi, "main"); + return -EPERM; + } + } + + /* zero the fractional part first */ + ret = di_write_wait(imxdi, 0, DTCLR); + if (ret) + return ret; + + ret = di_write_wait(imxdi, secs, DTCMR); + if (ret) + return ret; + + return di_write_wait(imxdi, readl(imxdi->ioaddr + DCR) | DCR_TCE, DCR); +} + +static const struct rtc_class_ops dryice_rtc_ops = { + .read_time = dryice_rtc_read_time, + .set_time = dryice_rtc_set_time, +}; + +static int nvstore_write(struct device_d *dev, const int reg, const void *val, + int bytes) +{ + struct imxdi_dev *imxdi = dev->parent->priv; + const u32 *val32 = val; + + if (bytes != 4) + return 0; + + writel(*val32, imxdi->ioaddr + DGPR); + + return 0; +} + +static int nvstore_read(struct device_d *dev, const int reg, void *val, + int bytes) +{ + struct imxdi_dev *imxdi = dev->parent->priv; + u32 *val32 = val; + + if (bytes != 4) + return 0; + + *val32 = readl(imxdi->ioaddr + DGPR); + + return 0; +} + +static struct nvmem_bus nvstore_nvmem_bus = { + .write = nvstore_write, + .read = nvstore_read, +}; + +static struct nvmem_config nvstore_nvmem_config = { + .name = "nvstore", + .stride = 4, + .word_size = 4, + .size = 4, + .bus = &nvstore_nvmem_bus, +}; + +static int __init dryice_rtc_probe(struct device_d *dev) +{ + struct resource *res; + struct imxdi_dev *imxdi; + int ret; + + imxdi = xzalloc(sizeof(*imxdi)); + + imxdi->dev = dev; + imxdi->rtc.ops = &dryice_rtc_ops; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + imxdi->ioaddr = IOMEM(res->start); + + imxdi->clk = clk_get(dev, NULL); + if (IS_ERR(imxdi->clk)) + return PTR_ERR(imxdi->clk); + + ret = clk_enable(imxdi->clk); + if (ret) + return ret; + + /* + * Initialize dryice hardware + */ + + /* mask all interrupts */ + writel(0, imxdi->ioaddr + DIER); + + ret = di_handle_state(imxdi); + if (ret) + goto err; + + dev->priv = imxdi; + + nvstore_nvmem_config.dev = dev; + + imxdi->nvmem = nvmem_register(&nvstore_nvmem_config); + if (IS_ENABLED(CONFIG_NVMEM) && IS_ERR(imxdi->nvmem)) { + ret = PTR_ERR(imxdi->nvmem); + goto err; + } + + ret = rtc_register(&imxdi->rtc); + if (ret) + goto err; + + return 0; + +err: + clk_disable(imxdi->clk); + + return ret; +} + +static __maybe_unused const struct of_device_id dryice_dt_ids[] = { + { .compatible = "fsl,imx25-rtc" }, + { /* sentinel */ } +}; + +static struct driver_d dryice_rtc_driver = { + .name = "imx-di-rtc", + .probe = dryice_rtc_probe, + .of_compatible = DRV_OF_COMPAT(dryice_dt_ids), +}; +device_platform_driver(dryice_rtc_driver); -- cgit v1.2.3 From 2bbbd2367a15a247cfe8261de6165341a9db36e8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 8 Oct 2018 16:21:17 +0200 Subject: ARM: i.MX: Add missing quotes to HAB specific defines The Freescale Code Signing Tool (cst) needs quotes around the filenames passed in the csf file. Add these quotes when the CONFIG_HAB* variables are passed from the command line. Signed-off-by: Sascha Hauer --- scripts/Makefile.lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 8c07a54d05..95eaf522ab 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -470,7 +470,7 @@ cmd_imximage_S_dcd= \ overwrite-hab-env = $(shell set -e; \ test -n "$(CONFIG_HAB_CERTS_ENV)"; \ test -n "$$$(1)"; \ - echo -D$(1)=\"$(shell echo $$$(1))\") + echo -D$(1)=\\\"$(shell echo $$$(1))\\\") imxcfg_cpp_flags = -Wp,-MD,$(depfile) -nostdinc -x assembler-with-cpp \ -I $(srctree)/include -I $(srctree)/arch/arm/mach-imx/include \ -- cgit v1.2.3 From 577df55b2fce18a5a433a4b0f9a6a7e3966909fe Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 11 Apr 2019 17:43:26 +0200 Subject: ARM: imx8mq: link PCIE1 and PCIE2 power domains Those two power domains can only be used together. The link between the two has been dropped with the dts merge of v5.1-rc1. Fix this. Fortunately the i.MX8MQ PCIe support will land in Linux 5.2, so we can drop all those PCIe related local DT overrides with the next big dts upstream sync. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/imx8mq.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/imx8mq.dtsi b/arch/arm/dts/imx8mq.dtsi index d1d8bdaa0e..1d59615238 100644 --- a/arch/arm/dts/imx8mq.dtsi +++ b/arch/arm/dts/imx8mq.dtsi @@ -198,3 +198,7 @@ <25000000>, <125000000>; }; + +&pgc_pcie1 { + power-domains = <&pgc_pcie2>; +}; -- cgit v1.2.3 From 53241aec68a7fc0ce3d56727a2b0ad140ec84ea5 Mon Sep 17 00:00:00 2001 From: Alexander Kurz Date: Fri, 12 Apr 2019 04:57:11 +0000 Subject: mtd: spi-nor: add Winbond W25Q40BW This 4MBit SPI chip can be found in Kindle Voyage devices Signed-off-by: Alexander Kurz Signed-off-by: Sascha Hauer --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 85b55c6982..1595349c4c 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -646,6 +646,7 @@ static const struct spi_device_id spi_nor_ids[] = { { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25q40bw", INFO(0xef5013, 0, 64 * 1024, 8, SECT_4K) }, { "w25q16dw", INFO(0xef6015, 0, 64 * 1024, 32, SECT_4K) }, { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, -- cgit v1.2.3 From b0baa61afb087d17118082ba04742cadb174436e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:21:19 -0700 Subject: ARM: zii-vf610-dev: Use -fno-tree-switch-conversion -fno-jump-tables Original and very poor workaround no longer works against GCC8, so drop it and replace with a proper solution that should've been used in the first place - specifying -fno-tree-switch-conversion -fno-jump-tables as CFLAGS when building lowlevel.c Tested to work with: - GCC 8.2.1 (arm-none-eabi) - GCC 7.1.0 (arm-none-eabi) - GCC 4.8.4 (armv7l-timesys-linux-gnueabihf) Signed-off-by: Andrey Smirnov Cc: Heiner Kallweit Cc: Chris Healy Signed-off-by: Sascha Hauer --- arch/arm/boards/zii-vf610-dev/Makefile | 1 + arch/arm/boards/zii-vf610-dev/lowlevel.c | 17 ----------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/arch/arm/boards/zii-vf610-dev/Makefile b/arch/arm/boards/zii-vf610-dev/Makefile index 1297d815e3..3c3a3f2387 100644 --- a/arch/arm/boards/zii-vf610-dev/Makefile +++ b/arch/arm/boards/zii-vf610-dev/Makefile @@ -1,3 +1,4 @@ obj-y += board.o +CFLAGS_pbl-lowlevel.o := -fno-tree-switch-conversion -fno-jump-tables lwl-y += lowlevel.o bbenv-y += defaultenv-zii-vf610-dev diff --git a/arch/arm/boards/zii-vf610-dev/lowlevel.c b/arch/arm/boards/zii-vf610-dev/lowlevel.c index 79588ac381..0db6459319 100644 --- a/arch/arm/boards/zii-vf610-dev/lowlevel.c +++ b/arch/arm/boards/zii-vf610-dev/lowlevel.c @@ -93,23 +93,6 @@ ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2) switch (system_type) { default: - /* - * GCC can be smart enough to, when DEBUG_LL is - * disabled, reduce this switch statement to a LUT - * fetch. Unfortunately here, this early in the boot - * process before any relocation/address fixups could - * happen, the address of that LUT used by the code is - * incorrect and any access to it would result in - * bogus values. - * - * Adding the following barrier() statement seem to - * force the compiler to always translate this block - * to a sequence of consecutive checks and jumps with - * relative fetches, which should work with or without - * relocation/fixups. - */ - barrier(); - if (IS_ENABLED(CONFIG_DEBUG_LL)) { relocate_to_current_adr(); setup_c(); -- cgit v1.2.3 From 598144bc8ef80576e3d54d4cb8d4207b22f64b46 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:21:20 -0700 Subject: ARM: zii-imx51-rdu1: Use -fno-tree-switch-conversion -fno-jump-tables Original and very poor workaround no longer works against GCC8, so drop it and replace with a proper solution that should've been used in the first place - specifying -fno-tree-switch-conversion -fno-jump-tables as CFLAGS when building lowlevel.c Tested to work with: - GCC 8.2.1 (arm-none-eabi) - GCC 7.1.0 (arm-none-eabi) - GCC 4.8.4 (armv7l-timesys-linux-gnueabihf) Signed-off-by: Andrey Smirnov Cc: Heiner Kallweit Cc: Chris Healy Signed-off-by: Sascha Hauer --- arch/arm/boards/zii-imx51-rdu1/Makefile | 1 + arch/arm/boards/zii-imx51-rdu1/lowlevel.c | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/arm/boards/zii-imx51-rdu1/Makefile b/arch/arm/boards/zii-imx51-rdu1/Makefile index 01c7a259e9..604b3621be 100644 --- a/arch/arm/boards/zii-imx51-rdu1/Makefile +++ b/arch/arm/boards/zii-imx51-rdu1/Makefile @@ -1,2 +1,3 @@ obj-y += board.o +CFLAGS_pbl-lowlevel.o := -fno-tree-switch-conversion -fno-jump-tables lwl-y += lowlevel.o diff --git a/arch/arm/boards/zii-imx51-rdu1/lowlevel.c b/arch/arm/boards/zii-imx51-rdu1/lowlevel.c index 849c5624c5..da05b0564c 100644 --- a/arch/arm/boards/zii-imx51-rdu1/lowlevel.c +++ b/arch/arm/boards/zii-imx51-rdu1/lowlevel.c @@ -84,13 +84,6 @@ ENTRY_FUNCTION(start_imx51_zii_rdu1, r0, r1, r2) switch (system_type) { default: - /* - * see similar code in - * arch/arm/boards/zii-vf610-dev/lowlevel.c for - * reasoning for placing barrier() below. - */ - barrier(); - if (IS_ENABLED(CONFIG_DEBUG_LL)) { relocate_to_current_adr(); setup_c(); -- cgit v1.2.3 From 07290094587d9e1142d530dc164ef2bdb6c47470 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:21:21 -0700 Subject: ARM: zii-imx8mq-dev: Drop unnecessary barrier() in switch statement AArch64 uses PC-relative addressing instead of absolute one for data lookups, so compiling switch statement into a LUT shouldn't be a problem regardless if relocation happened or not. Disassembly of PBL code looks almost exactly the same with or without this workaround, so it is clearly not needed. Drop it. Signed-off-by: Andrey Smirnov Cc: Heiner Kallweit Cc: Chris Healy Signed-off-by: Sascha Hauer --- arch/arm/boards/zii-imx8mq-dev/lowlevel.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/boards/zii-imx8mq-dev/lowlevel.c b/arch/arm/boards/zii-imx8mq-dev/lowlevel.c index 0fd2ddfca5..33c007e05d 100644 --- a/arch/arm/boards/zii-imx8mq-dev/lowlevel.c +++ b/arch/arm/boards/zii-imx8mq-dev/lowlevel.c @@ -179,13 +179,6 @@ ENTRY_FUNCTION(start_zii_imx8mq_dev, r0, r1, r2) switch (system_type) { default: - /* - * see similar code in - * arch/arm/boards/zii-vf610-dev/lowlevel.c for - * reasoning for placing barrier() below. - */ - barrier(); - if (IS_ENABLED(CONFIG_DEBUG_LL)) { relocate_to_current_adr(); setup_c(); -- cgit v1.2.3 From f0430fb6ffaef95377d249eb448325a5ac3e4db9 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 25 Apr 2019 15:53:18 -0700 Subject: ARM: zii-vf610-dev: Add ZII SSMB DTU board Add the Zodiac Digital Tapping Unit, a VF610 based network device with 5 Ethernet ports. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- arch/arm/boards/zii-vf610-dev/board.c | 4 +++- arch/arm/boards/zii-vf610-dev/lowlevel.c | 5 +++++ arch/arm/dts/Makefile | 3 ++- arch/arm/dts/vf610-zii-ssmb-dtu.dts | 16 ++++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 arch/arm/dts/vf610-zii-ssmb-dtu.dts diff --git a/arch/arm/boards/zii-vf610-dev/board.c b/arch/arm/boards/zii-vf610-dev/board.c index 1296f70317..90d4535684 100644 --- a/arch/arm/boards/zii-vf610-dev/board.c +++ b/arch/arm/boards/zii-vf610-dev/board.c @@ -122,6 +122,7 @@ static int zii_vf610_dev_set_hostname(void) const char *compatible; const char *hostname; } boards[] = { + { "zii,vf610dtu", "dtu" }, { "zii,vf610spu3", "spu3" }, { "zii,vf610spb4", "spb4" }, { "zii,vf610cfu1", "cfu1" }, @@ -170,7 +171,8 @@ static int zii_vf610_register_emmc_bbu(void) if (!of_machine_is_compatible("zii,vf610spu3") && !of_machine_is_compatible("zii,vf610cfu1") && - !of_machine_is_compatible("zii,vf610spb4")) + !of_machine_is_compatible("zii,vf610spb4") && + !of_machine_is_compatible("zii,vf610dtu")) return 0; ret = vf610_bbu_internal_mmcboot_register_handler("eMMC", diff --git a/arch/arm/boards/zii-vf610-dev/lowlevel.c b/arch/arm/boards/zii-vf610-dev/lowlevel.c index 0db6459319..b320fbc0cf 100644 --- a/arch/arm/boards/zii-vf610-dev/lowlevel.c +++ b/arch/arm/boards/zii-vf610-dev/lowlevel.c @@ -42,6 +42,7 @@ enum zii_platform_vf610_type { ZII_PLATFORM_VF610_CFU1 = 0x04, ZII_PLATFORM_VF610_DEV_REV_C = 0x05, ZII_PLATFORM_VF610_SPB4 = 0x06, + ZII_PLATFORM_VF610_SSMB_DTU = 0x07, }; static unsigned int get_system_type(void) @@ -79,6 +80,7 @@ extern char __dtb_vf610_zii_dev_rev_c_start[]; extern char __dtb_vf610_zii_cfu1_start[]; extern char __dtb_vf610_zii_ssmb_spu3_start[]; extern char __dtb_vf610_zii_scu4_aib_start[]; +extern char __dtb_vf610_zii_ssmb_dtu_start[]; extern char __dtb_vf610_zii_spb4_start[]; ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2) @@ -120,6 +122,9 @@ ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2) case ZII_PLATFORM_VF610_SPB4: fdt = __dtb_vf610_zii_spb4_start; break; + case ZII_PLATFORM_VF610_SSMB_DTU: + fdt = __dtb_vf610_zii_ssmb_dtu_start; + break; } vf610_barebox_entry(fdt + get_runtime_offset()); diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 1c6129816d..be3edbb0cc 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -125,7 +125,8 @@ pbl-dtb-$(CONFIG_MACH_ZII_VF610_DEV) += \ vf610-zii-cfu1.dtb.o \ vf610-zii-ssmb-spu3.dtb.o \ vf610-zii-scu4-aib.dtb.o \ - vf610-zii-spb4.dtb.o + vf610-zii-spb4.dtb.o \ + vf610-zii-ssmb-dtu.dtb.o pbl-dtb-$(CONFIG_MACH_AT91SAM9263EK_DT) += at91sam9263ek.dtb.o pbl-dtb-$(CONFIG_MACH_MICROCHIP_KSZ9477_EVB) += at91-microchip-ksz9477-evb.dtb.o pbl-dtb-$(CONFIG_MACH_AT91SAM9X5EK) += at91sam9x5ek.dtb.o diff --git a/arch/arm/dts/vf610-zii-ssmb-dtu.dts b/arch/arm/dts/vf610-zii-ssmb-dtu.dts new file mode 100644 index 0000000000..6ffb7aa62d --- /dev/null +++ b/arch/arm/dts/vf610-zii-ssmb-dtu.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +#include + +#include "vf610-zii-dev.dtsi" + +/ { + aliases { + /* + * NVMEM device corresponding to EEPROM attached to + * the switch shared DT node with it, so we use that + * fact to create a desirable naming + */ + switch-eeprom = &switch0; + }; +}; \ No newline at end of file -- cgit v1.2.3 From 5352e27eb4e2c43bc6572bf0320177683068eb8e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 27 Apr 2019 12:09:05 +0200 Subject: clk: vf610: improve handling case that cpu frequency can't be changed Currently we get a nasty error message if the cpu clock can't be changed: DDRC is clocked by PLL1, can't switch CPU clockinitcall vf610_switch_cpu_clock+0x1/0x198 failed: Invalid argument So let's do the following: - factor out the check from vf610_switch_cpu_clock_to_500mhz() and vf610_switch_cpu_clock_to_400mhz - if clock can't be changed, don't treat it as an error - don't call clock notifier chain if clock can't be changed - add trailing newline to the warning message Signed-off-by: Heiner Kallweit Reviewed-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/clk/imx/clk-vf610.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 1b1b881052..d70f4416cb 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -459,26 +459,30 @@ enum { DDRMC_CR117_AXI0_FITYPEREG_SYNC = 0b01 << 16, }; -static int vf610_switch_cpu_clock_to_500mhz(void) +static bool vf610_cpu_clk_changeable(void) { - int ret; - /* * When switching A5 CPU to 500Mhz we expect DDRC to be * clocked by PLL2_PFD2 and the system to be configured in * asynchronous mode. - * - * We also can't just use default PFD1 output of PLL1 due to - * Errata e6235, so we have to re-clock the PLL itself and use - * its output to clock the CPU directly. */ - if (clk_get_parent(clk[VF610_CLK_DDR_SEL]) != clk[VF610_CLK_PLL2_PFD2]) { - pr_warn("DDRC is clocked by PLL1, can't switch CPU clock"); - return -EINVAL; + pr_warn("DDRC is clocked by PLL1, can't switch CPU clock\n"); + return false; } + return true; +} + +static int vf610_switch_cpu_clock_to_500mhz(void) +{ + int ret; + /* + * We can't just use default PFD1 output of PLL1 due to + * Errata e6235, so we have to re-clock the PLL itself and use + * its output to clock the CPU directly. + * * Code below alters the frequency of PLL1, and doing so would * require us to wait for PLL1 lock before proceeding to * select it as a clock source again. @@ -533,11 +537,6 @@ static int vf610_switch_cpu_clock_to_400mhz(void) uint32_t cr117; void * __iomem ddrmc = IOMEM(VF610_DDR_BASE_ADDR); - if (clk_get_parent(clk[VF610_CLK_DDR_SEL]) != clk[VF610_CLK_PLL2_PFD2]) { - pr_warn("DDRC is clocked by PLL1, can't switch CPU clock"); - return -EINVAL; - } - ret = clk_set_parent(clk[VF610_CLK_PLL2_PFD_SEL], clk[VF610_CLK_PLL2_PFD2]); if (ret < 0) { pr_crit("Unable to re-parent '%s'\n", @@ -595,10 +594,14 @@ static int vf610_switch_cpu_clock(void) return 0; case VF610_SPEED_500: + if (!vf610_cpu_clk_changeable()) + return 0; ret = vf610_switch_cpu_clock_to_500mhz(); break; case VF610_SPEED_400: + if (!vf610_cpu_clk_changeable()) + return 0; ret = vf610_switch_cpu_clock_to_400mhz(); break; } -- cgit v1.2.3 From 4647cb602f486f61ec5ca4e6ab0eabdfccceb5db Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 30 Apr 2019 09:18:25 +0200 Subject: Documentation: imx: add documentation for RioTboard Signed-off-by: Oleksij Rempel Signed-off-by: Sascha Hauer --- .../boards/imx/embest-i.mx6s-riotboard.rst | 133 +++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 Documentation/boards/imx/embest-i.mx6s-riotboard.rst diff --git a/Documentation/boards/imx/embest-i.mx6s-riotboard.rst b/Documentation/boards/imx/embest-i.mx6s-riotboard.rst new file mode 100644 index 0000000000..9157f53c2a --- /dev/null +++ b/Documentation/boards/imx/embest-i.mx6s-riotboard.rst @@ -0,0 +1,133 @@ +Embest RIoTboard +================ + +RIoTboard Standard kit +---------------------- + +http://www.embest-tech.com/prod_view.aspx?TypeId=74&Id=345&FId=t3:74:3 + +General Features: + * Product Dimensions: 75mm x 120mm + * Operating Temperature: 0 ~ 50℃ + * Operating Humidity: 20% ~ 90% (non-condensing) + * DC-in:5V/4A + +Processor: + * i.MX 6Solo based on ARM Cortex™-A9 + * 32 Kbyte L1 instruction buffer + * 32 Kbyte L1 data buffer + * Private counter and watchdog + * Cortex-A9 NEON MPE (media processing engine) coprocessor + +On-Board Memories: + * 4GByte eMMC + * 2*512MB DDR3 SDRAM + +One-Board Interfaces/Buttons: + + * Audio input/output interfaces + * A LVDS interface + * A HDMI interface + * A LCD display interface (expansion interface) + * A digital camera interface + * A MIPI interface + * 4 TTL-level serial interfaces (one for debugging, the rest for expansion) + * 4 high-speed USB2.0 host interfaces (480Mbps) + * A high-speed USB2.0 OTG interface (480Mbps) + * A SD card slot + * A TF card slot + * A 10/100M/1Gbps RJ45 interface + * 2 I2C interfaces (expansion interfaces) + * 2 SPI interfaces (expansion interfaces) + * 3 PWM interfaces (expansion interfaces) + * A GPIO interface (expansion interfaces) + * A JTAG interface + * A boot-mode switch + * 4 LEDs (1 system LED, 2 custom LED, 1 open SDA LED) + * A reset button + +How to build barebox for Embest RIoTboard +----------------------------------------- + +Using the default configuration: + +.. code-block:: sh + + make ARCH=arm imx_v7_defconfig + +Build the binary image: + +.. code-block:: sh + + make ARCH=arm CROSS_COMPILE=armv7compiler + +.. note:: replace ``armv7compiler`` with your ARM v7 cross compiler prefix, + e.g.: ``arm-linux-gnueabihf-`` + +The resulting binary image to be flashed will be ``images/barebox-embest-imx6s-riotboard.img``. + +Replacing U-Boot with barebox +----------------------------- + + 1. Connect to the boards's UART (115200 8N1); + + 2. Turn board's power on; + + 3. Wait ``Hit any key to stop autoboot: 2`` prompt and press any key; + + 4. Upload barebox image to the board via tftp and start it + +.. code-block:: none + + MX6Solo RIoTboard U-Boot > setenv ethaddr d2:2d:ce:88:f4:f1 + MX6Solo RIoTboard U-Boot > tftpboot 0x20800000 192.168.23.4:ore-barebox-riotboard + ----phy_addr=0x4, id= 0x4dd072 + FEC: Link is Up 796d + Using FEC0 device + TFTP from server 192.168.23.4; our IP address is 192.168.1.103 + Filename 'ore-barebox-riotboard'. + Load address: 0x20800000 + Loading: ## Warning: gatewayip needed but not set + ## Warning: gatewayip needed but not set + ############################################ + done + Bytes transferred = 637947 (9bbfb hex) + MX6Solo RIoTboard U-Boot > go 0x20800000 + + ## Starting application at 0x20800000 ... + + barebox 2019.04.0-00151-g86762248de #391 Mon Apr 29 14:41:58 CEST 2019 + + Board: RIoTboard i.MX6S + detected i.MX6 Solo revision 1.1 + i.MX reset reason POR (SRSR: 0x00000001) + mdio_bus: miibus0: probed + imx-usb 2184200.usb@2184200.of: USB EHCI 1.00 + imx-esdhc 2194000.usdhc@2194000.of: registered as mmc1 + imx-esdhc 2198000.usdhc@2198000.of: registered as mmc2 + imx-esdhc 219c000.usdhc@219c000.of: registered as mmc3 + imx-ipuv3 2400000.ipu@2400000.of: IPUv3H probed + imx-hdmi 120000.hdmi@120000.of: Detected HDMI controller 0x13:0x1a:0xa0:0xc1 + netconsole: registered as netconsole-1 + malloc space: 0x2fefb5e0 -> 0x4fdf6bbf (size 511 MiB) + mmc3: detected MMC card version 4.41 + mmc3: registered mmc3.boot0 + mmc3: registered mmc3.boot1 + mmc3: registered mmc3 + partition mmc3.3 not completely inside device mmc3 + mmc3: Failed to register partition 3 on mmc3 (-22) + envfs: no envfs (magic mismatch) - envfs never written? + running /env/bin/init... + + Hit m for menu or any key to stop autoboot: 2 + + type exit to get to the menu + barebox@RIoTboard i.MX6S:/ +.. + + 5. Install barebox to the eMMC + +.. code-block:: none + + barebox@RIoTboard i.MX6S:/ cp /mnt/tftp/ore-barebox-riotboard /dev/mmc3.barebox +.. -- cgit v1.2.3