From 185dcf7f56dde4953ccb8b43355355e86376efb8 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 6 Jul 2020 10:37:55 +0200 Subject: msm_serial: Read bit rate register value from DT IPQ40xx and currently supported Snapdragon boards don't use the same one so enable reading it from DT, if no DT property is found default value is the same as the previous define. Signed-off-by: Robert Marko Reviewed-By: Ramon Fried --- doc/device-tree-bindings/serial/msm-serial.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'doc') diff --git a/doc/device-tree-bindings/serial/msm-serial.txt b/doc/device-tree-bindings/serial/msm-serial.txt index 48b8428aca8..dca995798a9 100644 --- a/doc/device-tree-bindings/serial/msm-serial.txt +++ b/doc/device-tree-bindings/serial/msm-serial.txt @@ -4,3 +4,7 @@ Required properties: - compatible: must be "qcom,msm-uartdm-v1.4" - reg: start address and size of the registers - clock: interface clock (must accept baudrate as a frequency) + +Optional properties: +- bit-rate: Data Mover bit rate register value + (If not defined then 0xCC is used as default) -- cgit v1.3.1 From 0c7eb6e525decee1b9ce9096888338896ffbb460 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 6 Jul 2020 10:37:56 +0200 Subject: msm_gpio: Add support for Qualcomm IPQ40xx Snapdragon SoCs and IPQ40xx use common TLMM IP, so existing driver supports IPQ40xx as well. So lets simply add a compatible for IPQ40xx. Signed-off-by: Robert Marko Reviewed-By: Ramon Fried --- doc/device-tree-bindings/gpio/gpio-msm.txt | 3 ++- drivers/gpio/msm_gpio.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/device-tree-bindings/gpio/gpio-msm.txt b/doc/device-tree-bindings/gpio/gpio-msm.txt index 966ce0af09c..70a2c7f0ddb 100644 --- a/doc/device-tree-bindings/gpio/gpio-msm.txt +++ b/doc/device-tree-bindings/gpio/gpio-msm.txt @@ -1,7 +1,8 @@ Qualcomm Snapdragon GPIO controller Required properties: -- compatible : "qcom,msm8916-pinctrl" or "qcom,apq8016-pinctrl" +- compatible : "qcom,msm8916-pinctrl", "qcom,apq8016-pinctrl" or + "qcom,ipq4019-pinctrl" - reg : Physical base address and length of the controller's registers. This controller is called "Top Level Mode Multiplexing" in Qualcomm documentation. diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index fe6b33e1dff..416fb56a98d 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -118,6 +118,7 @@ static int msm_gpio_ofdata_to_platdata(struct udevice *dev) static const struct udevice_id msm_gpio_ids[] = { { .compatible = "qcom,msm8916-pinctrl" }, { .compatible = "qcom,apq8016-pinctrl" }, + { .compatible = "qcom,ipq4019-pinctrl" }, { } }; -- cgit v1.3.1 From c25e9e04a12e93cd1a1928e941a3802d44765ccb Mon Sep 17 00:00:00 2001 From: Stefan Bosch Date: Fri, 10 Jul 2020 19:07:28 +0200 Subject: i2c: add nexell driver Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01: - i2c/nx_i2c.c: Some adaptions mainly because of changes in "struct udevice". - several Bugfixes in nx_i2c.c. - the driver has been for s5p6818 only. Code extended appropriately in order s5p4418 is also working. - "probe_chip" added. - pinctrl-driver/dt is used instead of configuring the i2c I/O-pins in the i2c-driver. - '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where possible (and similar). - livetree API (dev_read_...) is used instead of fdt one (fdt...). Signed-off-by: Stefan Bosch --- doc/device-tree-bindings/i2c/nx_i2c.txt | 28 ++ drivers/i2c/Kconfig | 9 + drivers/i2c/Makefile | 1 + drivers/i2c/nx_i2c.c | 626 ++++++++++++++++++++++++++++++++ 4 files changed, 664 insertions(+) create mode 100644 doc/device-tree-bindings/i2c/nx_i2c.txt create mode 100644 drivers/i2c/nx_i2c.c (limited to 'doc') diff --git a/doc/device-tree-bindings/i2c/nx_i2c.txt b/doc/device-tree-bindings/i2c/nx_i2c.txt new file mode 100644 index 00000000000..9f3abe78e4e --- /dev/null +++ b/doc/device-tree-bindings/i2c/nx_i2c.txt @@ -0,0 +1,28 @@ +I2C controller embedded in Nexell's/Samsung's SoC S5P4418 and S5P6818 + +Driver: +- drivers/i2c/nx_i2c.c + +Required properties: +- #address-cells = <1>; +- #size-cells = <0>; +- compatible = "nexell,s5pxx18-i2c"; +- reg = ; + Where i2c_base has to be the base address of the i2c-register set. + I2C0: 0xc00a4000 + I2C1: 0xc00a5000 + I2C2: 0xc00a6000 + +Optional properties: +- clock-frequency: Desired I2C bus frequency in Hz, default value is 100000. +- i2c-sda-delay-ns (S5P6818 only): SDA delay in ns, default value is 0. +- Child nodes conforming to i2c bus binding. + +Example: + i2c0:i2c@c00a4000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nexell,s5pxx18-i2c"; + reg = <0xc00a4000 0x100>; + clock-frequency = <400000>; + }; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 87d11b663c3..dec6dc9dfa4 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -333,6 +333,15 @@ config SYS_MXC_I2C8_SLAVE MXC I2C8 Slave endif +config SYS_I2C_NEXELL + bool "Nexell I2C driver" + depends on DM_I2C + help + Add support for the Nexell I2C driver. This is used with various + Nexell parts such as S5Pxx18 series SoCs. All chips + have several I2C ports and all are provided, controlled by the + device tree. + config SYS_I2C_OMAP24XX bool "TI OMAP2+ I2C driver" depends on ARCH_OMAP2PLUS || ARCH_K3 diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 174081e2529..e851ec462ec 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o +obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o obj-$(CONFIG_SYS_I2C_OCTEON) += octeon_i2c.o obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c new file mode 100644 index 00000000000..ca14a0ecac7 --- /dev/null +++ b/drivers/i2c/nx_i2c.c @@ -0,0 +1,626 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_WRITE 0 +#define I2C_READ 1 + +#define I2CSTAT_MTM 0xC0 /* Master Transmit Mode */ +#define I2CSTAT_MRM 0x80 /* Master Receive Mode */ +#define I2CSTAT_BSY 0x20 /* Read: Bus Busy */ +#define I2CSTAT_SS 0x20 /* Write: START (1) / STOP (0) */ +#define I2CSTAT_RXTXEN 0x10 /* Rx/Tx enable */ +#define I2CSTAT_ABT 0x08 /* Arbitration bit */ +#define I2CSTAT_NACK 0x01 /* Nack bit */ +#define I2CCON_IRCLR 0x100 /* Interrupt Clear bit */ +#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ +#define I2CCON_TCP256 0x40 /* Tx-clock prescaler: 16 (0) / 256 (1) */ +#define I2CCON_IRENB 0x20 /* Interrupt Enable bit */ +#define I2CCON_IRPND 0x10 /* Interrupt pending bit */ +#define I2CCON_TCDMSK 0x0F /* I2C-bus transmit clock divider bit mask */ + +#ifdef CONFIG_ARCH_S5P6818 +#define SDADLY_CLKSTEP 5 /* SDA delay: Reg. val. is multiple of 5 clks */ +#define SDADLY_MAX 3 /* SDA delay: Max. reg. value is 3 */ +#define I2CLC_FILTER 0x04 /* SDA filter on */ +#else +#define STOPCON_CLR 0x01 /* Clock Line Release */ +#define STOPCON_DLR 0x02 /* Data Line Release */ +#define STOPCON_NAG 0x04 /* not-ackn. generation and data shift cont. */ +#endif + +#define I2C_TIMEOUT_MS 10 /* 10 ms */ + +#define I2C_M_NOSTOP 0x100 + +#define MAX_I2C_NUM 3 + +#define DEFAULT_SPEED 100000 /* default I2C speed [Hz] */ + +DECLARE_GLOBAL_DATA_PTR; + +struct nx_i2c_regs { + uint iiccon; + uint iicstat; + uint iicadd; + uint iicds; +#ifdef CONFIG_ARCH_S5P6818 + /* S5P6818: Offset 0x10 is Line Control Register (SDA-delay, Filter) */ + uint iiclc; +#else + /* S5P4418: Offset 0x10 is Stop Control Register */ + uint iicstopcon; +#endif +}; + +struct nx_i2c_bus { + uint bus_num; + struct nx_i2c_regs *regs; + uint speed; + uint target_speed; +#ifdef CONFIG_ARCH_S5P6818 + uint sda_delay; +#else + /* setup time for Stop condition [us] */ + uint tsu_stop; +#endif +}; + +/* s5pxx18 i2c must be reset before enabled */ +static void i2c_reset(int ch) +{ + int rst_id = RESET_ID_I2C0 + ch; + + nx_rstcon_setrst(rst_id, 0); + nx_rstcon_setrst(rst_id, 1); +} + +static uint i2c_get_clkrate(struct nx_i2c_bus *bus) +{ + struct clk *clk; + int index = bus->bus_num; + char name[50] = {0, }; + + sprintf(name, "%s.%d", DEV_NAME_I2C, index); + clk = clk_get((const char *)name); + if (!clk) + return -1; + + return clk_get_rate(clk); +} + +static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb) +{ + struct clk *clk; + char name[50]; + + sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num); + clk = clk_get((const char *)name); + if (!clk) { + debug("%s(): clk_get(%s) error!\n", + __func__, (const char *)name); + return -EINVAL; + } + + clk_disable(clk); + if (enb) + clk_enable(clk); + + return 0; +} + +#ifdef CONFIG_ARCH_S5P6818 +/* Set SDA line delay, not available at S5P4418 */ +static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus) +{ + struct nx_i2c_regs *i2c = bus->regs; + uint pclk = 0; + uint t_pclk = 0; + uint delay = 0; + + /* get input clock of the I2C-controller */ + pclk = i2c_get_clkrate(bus); + + if (bus->sda_delay) { + /* t_pclk = period time of one pclk [ns] */ + t_pclk = DIV_ROUND_UP(1000, pclk / 1000000); + /* delay = number of pclks required for sda_delay [ns] */ + delay = DIV_ROUND_UP(bus->sda_delay, t_pclk); + /* delay = register value (step of 5 clocks) */ + delay = DIV_ROUND_UP(delay, SDADLY_CLKSTEP); + /* max. possible register value = 3 */ + if (delay > SDADLY_MAX) { + delay = SDADLY_MAX; + debug("%s(): sda-delay des.: %dns, sat. to max.: %dns (granularity: %dns)\n", + __func__, bus->sda_delay, t_pclk * delay * SDADLY_CLKSTEP, + t_pclk * SDADLY_CLKSTEP); + } else { + debug("%s(): sda-delay des.: %dns, act.: %dns (granularity: %dns)\n", + __func__, bus->sda_delay, t_pclk * delay * SDADLY_CLKSTEP, + t_pclk * SDADLY_CLKSTEP); + } + + delay |= I2CLC_FILTER; + } else { + delay = 0; + debug("%s(): sda-delay = 0\n", __func__); + } + + delay &= 0x7; + writel(delay, &i2c->iiclc); + + return 0; +} +#endif + +static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + struct nx_i2c_regs *i2c = bus->regs; + unsigned long pclk, pres = 16, div; + + if (i2c_set_clk(bus, 1)) + return -EINVAL; + + /* get input clock of the I2C-controller */ + pclk = i2c_get_clkrate(bus); + + /* calculate prescaler and divisor values */ + if ((pclk / pres / (16 + 1)) > speed) + /* prescaler value 16 is too less --> set to 256 */ + pres = 256; + + div = 0; + /* actual divider = div + 1 */ + while ((pclk / pres / (div + 1)) > speed) + div++; + + if (div > 0xF) { + debug("%s(): pres==%ld, div==0x%lx is saturated to 0xF !)\n", + __func__, pres, div); + div = 0xF; + } else { + debug("%s(): pres==%ld, div==0x%lx)\n", __func__, pres, div); + } + + /* set Tx-clock divisor and prescaler values */ + writel((div & I2CCON_TCDMSK) | ((pres == 256) ? I2CCON_TCP256 : 0), + &i2c->iiccon); + + /* init to SLAVE REVEIVE and set slaveaddr */ + writel(0, &i2c->iicstat); + writel(0x00, &i2c->iicadd); + + /* program Master Transmit (and implicit STOP) */ + writel(I2CSTAT_MTM | I2CSTAT_RXTXEN, &i2c->iicstat); + + /* calculate actual I2C speed [Hz] */ + bus->speed = pclk / ((div + 1) * pres); + debug("%s(): speed des.: %dHz, act.: %dHz\n", + __func__, speed, bus->speed); + +#ifdef CONFIG_ARCH_S5P6818 + nx_i2c_set_sda_delay(bus); +#else + /* setup time for Stop condition [us], min. 4us @ 100kHz I2C-clock */ + bus->tsu_stop = DIV_ROUND_UP(400, bus->speed / 1000); +#endif + + if (i2c_set_clk(bus, 0)) + return -EINVAL; + return 0; +} + +static void i2c_process_node(struct udevice *dev) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + + bus->target_speed = dev_read_s32_default(dev, "clock-frequency", + DEFAULT_SPEED); +#ifdef CONFIG_ARCH_S5P6818 + bus->sda_delay = dev_read_s32_default(dev, "i2c-sda-delay-ns", 0); +#endif +} + +static int nx_i2c_probe(struct udevice *dev) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + fdt_addr_t addr; + + /* get regs = i2c base address */ + addr = devfdt_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + bus->regs = (struct nx_i2c_regs *)addr; + + bus->bus_num = dev->seq; + + /* i2c node parsing */ + i2c_process_node(dev); + if (!bus->target_speed) + return -ENODEV; + + /* reset */ + i2c_reset(bus->bus_num); + + return 0; +} + +/* i2c bus busy check */ +static int i2c_is_busy(struct nx_i2c_regs *i2c) +{ + ulong start_time; + + start_time = get_timer(0); + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) { + debug("Timeout\n"); + return -EBUSY; + } + } + return 0; +} + +/* irq enable/disable functions */ +static void i2c_enable_irq(struct nx_i2c_regs *i2c) +{ + unsigned int reg; + + reg = readl(&i2c->iiccon); + reg |= I2CCON_IRENB; + writel(reg, &i2c->iiccon); +} + +/* irq clear function */ +static void i2c_clear_irq(struct nx_i2c_regs *i2c) +{ + unsigned int reg; + + reg = readl(&i2c->iiccon); + /* reset interrupt pending flag */ + reg &= ~(I2CCON_IRPND); + /* + * Interrupt must also be cleared! + * Otherwise linux boot may hang after: + * [ 0.436000] NetLabel: unlabeled traffic allowed by default + * Next would be: + * [ 0.442000] clocksource: Switched to clocksource source timer + */ + reg |= I2CCON_IRCLR; + writel(reg, &i2c->iiccon); +} + +/* ack enable functions */ +static void i2c_enable_ack(struct nx_i2c_regs *i2c) +{ + unsigned int reg; + + reg = readl(&i2c->iiccon); + reg |= I2CCON_ACKGEN; + writel(reg, &i2c->iiccon); +} + +static void i2c_send_stop(struct nx_i2c_bus *bus) +{ + struct nx_i2c_regs *i2c = bus->regs; + + if (IS_ENABLED(CONFIG_ARCH_S5P6818)) { + unsigned int reg; + + reg = readl(&i2c->iicstat); + reg |= I2CSTAT_MRM | I2CSTAT_RXTXEN; + reg &= (~I2CSTAT_SS); + + writel(reg, &i2c->iicstat); + i2c_clear_irq(i2c); + } else { /* S5P4418 */ + writel(STOPCON_NAG, &i2c->iicstopcon); + + i2c_clear_irq(i2c); + + /* + * Clock Line Release --> SDC changes from Low to High and + * SDA from High to Low + */ + writel(STOPCON_CLR, &i2c->iicstopcon); + + /* Hold SDA Low (Setup Time for Stop condition) */ + udelay(bus->tsu_stop); + + i2c_clear_irq(i2c); + + /* Master Receive Mode Stop --> SDA becomes High */ + writel(I2CSTAT_MRM, &i2c->iicstat); + } +} + +static int wait_for_xfer(struct nx_i2c_regs *i2c) +{ + unsigned long start_time = get_timer(0); + + do { + if (readl(&i2c->iiccon) & I2CCON_IRPND) + /* return -EREMOTEIO if not Acknowledged, otherwise 0 */ + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ? + -EREMOTEIO : 0; + } while (get_timer(start_time) < I2C_TIMEOUT_MS); + + return -ETIMEDOUT; +} + +static int i2c_transfer(struct nx_i2c_regs *i2c, + uchar cmd_type, + uchar chip_addr, + uchar addr[], + uchar addr_len, + uchar data[], + unsigned short data_len, + uint seq) +{ + uint status; + int i = 0, result; + + /* Note: data_len = 0 is supported for "probe_chip" */ + + i2c_enable_irq(i2c); + i2c_enable_ack(i2c); + + /* Get the slave chip address going */ + /* Enable Rx/Tx */ + writel(I2CSTAT_RXTXEN, &i2c->iicstat); + + writel(chip_addr, &i2c->iicds); + status = I2CSTAT_RXTXEN | I2CSTAT_SS; + if (cmd_type == I2C_WRITE || (addr && addr_len)) + status |= I2CSTAT_MTM; + else + status |= I2CSTAT_MRM; + + writel(status, &i2c->iicstat); + if (seq) + i2c_clear_irq(i2c); + + /* Wait for chip address to transmit. */ + result = wait_for_xfer(i2c); + if (result) { + debug("%s: transmitting chip address failed\n", __func__); + goto bailout; + } + + /* If register address needs to be transmitted - do it now. */ + if (addr && addr_len) { /* register addr */ + while ((i < addr_len) && !result) { + writel(addr[i++], &i2c->iicds); + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + } + + i = 0; + if (result) { + debug("%s: transmitting register address failed\n", + __func__); + goto bailout; + } + } + + switch (cmd_type) { + case I2C_WRITE: + while ((i < data_len) && !result) { + writel(data[i++], &i2c->iicds); + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + } + break; + case I2C_READ: + if (addr && addr_len) { + /* + * Register address has been sent, now send slave chip + * address again to start the actual read transaction. + */ + writel(chip_addr, &i2c->iicds); + + /* Generate a re-START. */ + writel(I2CSTAT_MRM | I2CSTAT_RXTXEN | + I2CSTAT_SS, &i2c->iicstat); + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + if (result) { + debug("%s: I2C_READ: sending chip addr. failed\n", + __func__); + goto bailout; + } + } + + while ((i < data_len) && !result) { + /* disable ACK for final READ */ + if (i == data_len - 1) + clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN); + + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + data[i++] = readb(&i2c->iicds); + } + + if (result == -EREMOTEIO) + /* Not Acknowledged --> normal terminated read. */ + result = 0; + else if (result == -ETIMEDOUT) + debug("%s: I2C_READ: time out\n", __func__); + else + debug("%s: I2C_READ: read not terminated with NACK\n", + __func__); + break; + + default: + debug("%s: bad call\n", __func__); + result = -EINVAL; + break; + } + +bailout: + return result; +} + +static int nx_i2c_read(struct udevice *dev, uchar chip_addr, uint addr, + uint alen, uchar *buffer, uint len, uint seq) +{ + struct nx_i2c_bus *i2c; + uchar xaddr[4]; + int ret; + + i2c = dev_get_priv(dev); + if (!i2c) + return -EFAULT; + + if (alen > 4) { + debug("I2C read: addr len %d not supported\n", alen); + return -EADDRNOTAVAIL; + } + + if (alen > 0) + xaddr[0] = (addr >> 24) & 0xFF; + + if (alen > 0) { + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + } + + ret = i2c_transfer(i2c->regs, I2C_READ, chip_addr << 1, + &xaddr[4 - alen], alen, buffer, len, seq); + + if (ret) { + debug("I2C read failed %d\n", ret); + return -EIO; + } + + return 0; +} + +static int nx_i2c_write(struct udevice *dev, uchar chip_addr, uint addr, + uint alen, uchar *buffer, uint len, uint seq) +{ + struct nx_i2c_bus *i2c; + uchar xaddr[4]; + int ret; + + i2c = dev_get_priv(dev); + if (!i2c) + return -EFAULT; + + if (alen > 4) { + debug("I2C write: addr len %d not supported\n", alen); + return -EINVAL; + } + + if (alen > 0) { + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + } + + ret = i2c_transfer(i2c->regs, I2C_WRITE, chip_addr << 1, + &xaddr[4 - alen], alen, buffer, len, seq); + if (ret) { + debug("I2C write failed %d\n", ret); + return -EIO; + } + + return 0; +} + +static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + struct nx_i2c_regs *i2c = bus->regs; + int ret; + int i; + + /* The power loss by the clock, only during on/off. */ + ret = i2c_set_clk(bus, 1); + + if (!ret) + /* Bus State(Busy) check */ + ret = i2c_is_busy(i2c); + if (!ret) { + for (i = 0; i < nmsgs; msg++, i++) { + if (msg->flags & I2C_M_RD) { + ret = nx_i2c_read(dev, msg->addr, 0, 0, + msg->buf, msg->len, i); + } else { + ret = nx_i2c_write(dev, msg->addr, 0, 0, + msg->buf, msg->len, i); + } + + if (ret) { + debug("i2c_xfer: error sending\n"); + ret = -EREMOTEIO; + } + } + + i2c_send_stop(bus); + if (i2c_set_clk(bus, 0)) + ret = -EINVAL; + } + + return ret; +}; + +static int nx_i2c_probe_chip(struct udevice *dev, u32 chip_addr, + u32 chip_flags) +{ + int ret; + struct nx_i2c_bus *bus = dev_get_priv(dev); + + ret = i2c_set_clk(bus, 1); + + if (!ret) { + /* + * Send Chip Address only + * --> I2C transfer with data length and address length = 0. + * If there is a Slave, i2c_transfer() returns 0 (acknowledge + * transfer). + * I2C_WRITE must be used in order Master Transmit Mode is + * selected. Otherwise (in Master Receive Mode, I2C_READ) + * sending the stop condition below is not working (SDA does + * not transit to High). + */ + ret = i2c_transfer(bus->regs, I2C_WRITE, (uchar)chip_addr << 1, + NULL, 0, NULL, 0, 0); + + i2c_send_stop(bus); + if (i2c_set_clk(bus, 0)) + ret = -EINVAL; + } + + return ret; +} + +static const struct dm_i2c_ops nx_i2c_ops = { + .xfer = nx_i2c_xfer, + .probe_chip = nx_i2c_probe_chip, + .set_bus_speed = nx_i2c_set_bus_speed, +}; + +static const struct udevice_id nx_i2c_ids[] = { + { .compatible = "nexell,s5pxx18-i2c" }, + { } +}; + +U_BOOT_DRIVER(i2c_nexell) = { + .name = "i2c_nexell", + .id = UCLASS_I2C, + .of_match = nx_i2c_ids, + .probe = nx_i2c_probe, + .priv_auto_alloc_size = sizeof(struct nx_i2c_bus), + .ops = &nx_i2c_ops, +}; -- cgit v1.3.1 From 8d393b2c2278c846d26d59b37a2b46d3bcdb1663 Mon Sep 17 00:00:00 2001 From: Stefan Bosch Date: Fri, 10 Jul 2020 19:07:30 +0200 Subject: pinctrl: add nexell driver Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01: - livetree API (dev_read_...) is used instead of fdt one (fdt...). - doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt added. Signed-off-by: Stefan Bosch --- .../pinctrl/nexell,s5pxx18-pinctrl.txt | 78 ++++++++ drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/nexell/Kconfig | 18 ++ drivers/pinctrl/nexell/Makefile | 7 + drivers/pinctrl/nexell/pinctrl-nexell.c | 66 +++++++ drivers/pinctrl/nexell/pinctrl-nexell.h | 68 +++++++ drivers/pinctrl/nexell/pinctrl-s5pxx18.c | 220 +++++++++++++++++++++ drivers/pinctrl/nexell/pinctrl-s5pxx18.h | 53 +++++ 9 files changed, 512 insertions(+) create mode 100644 doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt create mode 100644 drivers/pinctrl/nexell/Kconfig create mode 100644 drivers/pinctrl/nexell/Makefile create mode 100644 drivers/pinctrl/nexell/pinctrl-nexell.c create mode 100644 drivers/pinctrl/nexell/pinctrl-nexell.h create mode 100644 drivers/pinctrl/nexell/pinctrl-s5pxx18.c create mode 100644 drivers/pinctrl/nexell/pinctrl-s5pxx18.h (limited to 'doc') diff --git a/doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt b/doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt new file mode 100644 index 00000000000..115ab53a4cd --- /dev/null +++ b/doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt @@ -0,0 +1,78 @@ +Binding for Nexell s5pxx18 pin cotroller +======================================== + +Nexell's ARM bases SoC's integrates a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pads/pins +and also provides ability to multiplex and configure the output of various +on-chip controllers onto these pads. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + + +Required properties: + - compatible: "nexell,s5pxx18-pinctrl" + - reg: should be register base and length as documented in the datasheet + - interrupts: interrupt specifier for the controller over gpio and alive pins + +Example: +pinctrl_0: pinctrl@c0010000 { + compatible = "nexell,s5pxx18-pinctrl"; + reg = <0xc0010000 0xf000>; + u-boot,dm-pre-reloc; +}; + +Nexell's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters. + + Child nodes must be set at least one of the following settings: + - pins = Select pins for using this function. + - pin-function = Select the function for use in a selected pin. + - pin-pull = Pull up/down configuration. + - pin-strength = Drive strength configuration. + + Valid values for nexell,pins are: + "gpioX-N" : X in {A,B,C,D,E}, N in {0-31} + Valid values for nexell,pin-function are: + "N" : N in {0-3}. + This setting means that the value is different for each pin. + Please refer to datasheet. + Valid values for nexell,pin-pull are: + "N" : 0 - Down, 1 - Up, 2 - Off + Valid values for nexell,pin-strength are: + "N" : 0,1,2,3 + + +Example: + - pin settings + mmc0_clk: mmc0-clk { + pins = "gpioa-29"; + pin-function = <1>; + pin-pull = <2>; + pin-strength = <2>; + }; + + mmc0_cmd: mmc0-cmd { + pins = "gpioa-31"; + pin-function = <1>; + pin-pull = <2>; + pin-strength = <1>; + }; + + mmc0_bus4: mmc0-bus-width4 { + pins = "gpiob-1, gpiob-3, gpiob-5, gpiob-7"; + pin-function = <1>; + pin-pull = <2>; + pin-strength = <1>; + }; + + - used by client devices + mmc0:mmc@... { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_clk>, <&mmc0_cmd>, <&mmc0_bus4>; + ... + }; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 83e39b9de38..bd2061b765b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -294,6 +294,7 @@ source "drivers/pinctrl/meson/Kconfig" source "drivers/pinctrl/mscc/Kconfig" source "drivers/pinctrl/mtmips/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" +source "drivers/pinctrl/nexell/Kconfig" source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/rockchip/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 4f662c4f6da..92cff1b100d 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_PINCTRL_MSCC) += mscc/ obj-$(CONFIG_ARCH_MVEBU) += mvebu/ +obj-$(CONFIG_ARCH_NEXELL) += nexell/ obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o diff --git a/drivers/pinctrl/nexell/Kconfig b/drivers/pinctrl/nexell/Kconfig new file mode 100644 index 00000000000..8f1e4722396 --- /dev/null +++ b/drivers/pinctrl/nexell/Kconfig @@ -0,0 +1,18 @@ +if ARCH_NEXELL + +config PINCTRL_NEXELL + bool "Nexell pinctrl driver" + help + Support of pin multiplexing and pin configuration for Nexell + SoCs. + +config PINCTRL_NEXELL_S5PXX18 + bool "Nexell s5pxx18 SoC pinctrl driver" + default y if ARCH_S5P4418 || ARCH_S5P6818 + depends on ARCH_NEXELL && PINCTRL_FULL + select PINCTRL_NEXELL + help + Support of pin multiplexing and pin configuration for S5P4418 + and S5P6818 SoC. + +endif diff --git a/drivers/pinctrl/nexell/Makefile b/drivers/pinctrl/nexell/Makefile new file mode 100644 index 00000000000..74df414d559 --- /dev/null +++ b/drivers/pinctrl/nexell/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 Nexell +# Bongyu, KOO + +obj-$(CONFIG_PINCTRL_NEXELL) += pinctrl-nexell.o +obj-$(CONFIG_PINCTRL_NEXELL_S5PXX18) += pinctrl-s5pxx18.o diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.c b/drivers/pinctrl/nexell/pinctrl-nexell.c new file mode 100644 index 00000000000..4518c05d468 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-nexell.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO + */ + +#include +#include +#include +#include +#include "pinctrl-nexell.h" +#include "pinctrl-s5pxx18.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* given a pin-name, return the address of pin config registers */ +unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *pin_ctrl = priv->pin_ctrl; + const struct nexell_pin_bank_data *bank_data = pin_ctrl->pin_banks; + u32 nr_banks = pin_ctrl->nr_banks, idx = 0; + char bank[10]; + + /* + * The format of the pin name is -. + * Example: gpioa-4 (gpioa is the bank name and 4 is the pin number) + */ + while (pin_name[idx] != '-') { + bank[idx] = pin_name[idx]; + idx++; + } + bank[idx] = '\0'; + *pin = (u32)simple_strtoul(&pin_name[++idx], NULL, 10); + + /* lookup the pin bank data using the pin bank name */ + for (idx = 0; idx < nr_banks; idx++) + if (!strcmp(bank, bank_data[idx].name)) + break; + + return priv->base + bank_data[idx].offset; +} + +int nexell_pinctrl_probe(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv; + fdt_addr_t base; + + priv = dev_get_priv(dev); + if (!priv) + return -EINVAL; + + base = devfdt_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = base; + + priv->pin_ctrl = (struct nexell_pin_ctrl *)dev_get_driver_data(dev); + + s5pxx18_pinctrl_init(dev); + + return 0; +} diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.h b/drivers/pinctrl/nexell/pinctrl-nexell.h new file mode 100644 index 00000000000..b21eefcabef --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-nexell.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO + * + */ + +#ifndef __PINCTRL_NEXELL_H_ +#define __PINCTRL_NEXELL_H_ + +/** + * struct nexell_pin_bank_data: represent a controller pin-bank data. + * @offset: starting offset of the pin-bank registers. + * @nr_pins: number of pins included in this bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct nexell_pin_bank_data { + u32 offset; + u8 nr_pins; + const char *name; + u8 type; +}; + +#define NEXELL_PIN_BANK(pins, reg, id) \ + { \ + .offset = reg, \ + .nr_pins = pins, \ + .name = id \ + } + +/** + * struct nexell_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + */ +struct nexell_pin_ctrl { + const struct nexell_pin_bank_data *pin_banks; + u32 nr_banks; +}; + +/** + * struct nexell_pinctrl_priv: nexell pin controller driver private data + * @pin_ctrl: pin controller bank information. + * @base: base address of the pin controller instance. + */ +struct nexell_pinctrl_priv { + const struct nexell_pin_ctrl *pin_ctrl; + unsigned long base; +}; + +/** + * struct nexell_pinctrl_config_data: configuration for a peripheral. + * @offset: offset of the config registers in the controller. + * @mask: value of the register to be masked with. + * @value: new value to be programmed. + */ +struct nexell_pinctrl_config_data { + const unsigned int offset; + const unsigned int mask; + const unsigned int value; +}; + +unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin); +int nexell_pinctrl_probe(struct udevice *dev); + +#endif /* __PINCTRL_NEXELL_H_ */ diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.c b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c new file mode 100644 index 00000000000..96a2ed38a05 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO + * + * (C) Copyright 2019 Stefan Bosch + */ + +#include +#include +#include +#include +#include +#include +#include "pinctrl-nexell.h" +#include "pinctrl-s5pxx18.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void nx_gpio_set_bit(u32 *value, u32 bit, int enable) +{ + register u32 newvalue; + + newvalue = *value; + newvalue &= ~(1ul << bit); + newvalue |= (u32)enable << bit; + writel(newvalue, value); +} + +static void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value) +{ + register u32 newvalue = *value; + + newvalue = (u32)(newvalue & ~(3ul << (bit * 2))); + newvalue = (u32)(newvalue | (bit_value << (bit * 2))); + + writel(newvalue, value); +} + +static int nx_gpio_open_module(void *base) +{ + writel(0xFFFFFFFF, base + GPIOX_SLEW_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_DRV1_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_DRV0_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_PULLSEL_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_PULLENB_DISABLE_DEFAULT); + return true; +} + +static void nx_gpio_set_pad_function(void *base, u32 pin, u32 padfunc) +{ + u32 reg = (pin / 16) ? GPIOX_ALTFN1 : GPIOX_ALTFN0; + + nx_gpio_set_bit2(base + reg, pin % 16, padfunc); +} + +static void nx_gpio_set_drive_strength(void *base, u32 pin, u32 drv) +{ + nx_gpio_set_bit(base + GPIOX_DRV1, pin, (int)(((u32)drv >> 0) & 0x1)); + nx_gpio_set_bit(base + GPIOX_DRV0, pin, (int)(((u32)drv >> 1) & 0x1)); +} + +static void nx_gpio_set_pull_mode(void *base, u32 pin, u32 mode) +{ + if (mode == nx_gpio_pull_off) { + nx_gpio_set_bit(base + GPIOX_PULLENB, pin, false); + nx_gpio_set_bit(base + GPIOX_PULLSEL, pin, false); + } else { + nx_gpio_set_bit(base + GPIOX_PULLSEL, + pin, (mode & 1 ? true : false)); + nx_gpio_set_bit(base + GPIOX_PULLENB, pin, true); + } +} + +static void nx_alive_set_pullup(void *base, u32 pin, bool enable) +{ + u32 PULLUP_MASK; + + PULLUP_MASK = (1UL << pin); + if (enable) + writel(PULLUP_MASK, base + ALIVE_PADPULLUPSET); + else + writel(PULLUP_MASK, base + ALIVE_PADPULLUPRST); +} + +static int s5pxx18_pinctrl_gpio_init(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; + unsigned long reg = priv->base; + int i; + + for (i = 0; i < ctrl->nr_banks - 1; i++) /* except alive bank */ + nx_gpio_open_module((void *)(reg + ctrl->pin_banks[i].offset)); + + return 0; +} + +static int s5pxx18_pinctrl_alive_init(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; + unsigned long reg = priv->base; + + reg += ctrl->pin_banks[ctrl->nr_banks - 1].offset; + + writel(1, reg + ALIVE_PWRGATE); + return 0; +} + +int s5pxx18_pinctrl_init(struct udevice *dev) +{ + s5pxx18_pinctrl_gpio_init(dev); + s5pxx18_pinctrl_alive_init(dev); + + return 0; +} + +static int is_pin_alive(const char *name) +{ + return !strncmp(name, "alive", 5); +} + +/** + * s5pxx18_pinctrl_set_state: configure a pin state. + * dev: the pinctrl device to be configured. + * config: the state to be configured. + */ +static int s5pxx18_pinctrl_set_state(struct udevice *dev, + struct udevice *config) +{ + unsigned int count, idx, pin; + unsigned int pinfunc, pinpud, pindrv; + unsigned long reg; + const char *name; + int ret; + + /* + * refer to the following document for the pinctrl bindings + * doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt + */ + count = dev_read_string_count(config, "pins"); + + if (count <= 0) + return -EINVAL; + + pinfunc = dev_read_s32_default(config, "pin-function", -1); + pinpud = dev_read_s32_default(config, "pin-pull", -1); + pindrv = dev_read_s32_default(config, "pin-strength", -1); + + for (idx = 0; idx < count; idx++) { + ret = dev_read_string_index(config, "pins", idx, &name); + if (ret) + return ret; + if (!name) + continue; + reg = pin_to_bank_base(dev, name, &pin); + + if (is_pin_alive(name)) { + /* pin pull up/down */ + if (pinpud != -1) + nx_alive_set_pullup((void *)reg, pin, + pinpud & 1); + continue; + } + + /* pin function */ + if (pinfunc != -1) + nx_gpio_set_pad_function((void *)reg, pin, pinfunc); + + /* pin pull up/down/off */ + if (pinpud != -1) + nx_gpio_set_pull_mode((void *)reg, pin, pinpud); + + /* pin drive strength */ + if (pindrv != -1) + nx_gpio_set_drive_strength((void *)reg, pin, pindrv); + } + + return 0; +} + +static struct pinctrl_ops s5pxx18_pinctrl_ops = { + .set_state = s5pxx18_pinctrl_set_state, +}; + +/* pin banks of s5pxx18 pin-controller */ +static const struct nexell_pin_bank_data s5pxx18_pin_banks[] = { + NEXELL_PIN_BANK(32, 0xA000, "gpioa"), + NEXELL_PIN_BANK(32, 0xB000, "gpiob"), + NEXELL_PIN_BANK(32, 0xC000, "gpioc"), + NEXELL_PIN_BANK(32, 0xD000, "gpiod"), + NEXELL_PIN_BANK(32, 0xE000, "gpioe"), + NEXELL_PIN_BANK(6, 0x0800, "alive"), +}; + +const struct nexell_pin_ctrl s5pxx18_pin_ctrl[] = { + { + /* pin-controller data */ + .pin_banks = s5pxx18_pin_banks, + .nr_banks = ARRAY_SIZE(s5pxx18_pin_banks), + }, +}; + +static const struct udevice_id s5pxx18_pinctrl_ids[] = { + { .compatible = "nexell,s5pxx18-pinctrl", + .data = (ulong)s5pxx18_pin_ctrl }, + { } +}; + +U_BOOT_DRIVER(pinctrl_s5pxx18) = { + .name = "pinctrl_s5pxx18", + .id = UCLASS_PINCTRL, + .of_match = s5pxx18_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct nexell_pinctrl_priv), + .ops = &s5pxx18_pinctrl_ops, + .probe = nexell_pinctrl_probe, + .flags = DM_FLAG_PRE_RELOC +}; diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.h b/drivers/pinctrl/nexell/pinctrl-s5pxx18.h new file mode 100644 index 00000000000..843a00b9558 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO + */ + +#ifndef __PINCTRL_S5PXX18_H_ +#define __PINCTRL_S5PXX18_H_ + +#include +#include + +#define GPIOX_ALTFN0 0x20 +#define GPIOX_ALTFN1 0x24 +#define GPIOX_DRV1 0x48 +#define GPIOX_DRV0 0x50 +#define GPIOX_PULLSEL 0x58 +#define GPIOX_PULLENB 0x60 + +#define GPIOX_SLEW_DISABLE_DEFAULT 0x44 +#define GPIOX_DRV1_DISABLE_DEFAULT 0x4C +#define GPIOX_DRV0_DISABLE_DEFAULT 0x54 +#define GPIOX_PULLSEL_DISABLE_DEFAULT 0x5C +#define GPIOX_PULLENB_DISABLE_DEFAULT 0x64 + +#define ALIVE_PWRGATE 0x0 +#define ALIVE_PADPULLUPRST 0x80 +#define ALIVE_PADPULLUPSET 0x84 +#define ALIVE_PADPULLUPREAD 0x88 + +enum { + nx_gpio_padfunc_0 = 0ul, + nx_gpio_padfunc_1 = 1ul, + nx_gpio_padfunc_2 = 2ul, + nx_gpio_padfunc_3 = 3ul +}; + +enum { + nx_gpio_drvstrength_0 = 0ul, + nx_gpio_drvstrength_1 = 1ul, + nx_gpio_drvstrength_2 = 2ul, + nx_gpio_drvstrength_3 = 3ul +}; + +enum { + nx_gpio_pull_down = 0ul, + nx_gpio_pull_up = 1ul, + nx_gpio_pull_off = 2ul +}; + +int s5pxx18_pinctrl_init(struct udevice *dev); +#endif /* __PINCTRL_S5PXX18_H_ */ -- cgit v1.3.1 From b39cacc268a3feb3b21a0b966e1c293ab5c96a40 Mon Sep 17 00:00:00 2001 From: Stefan Bosch Date: Fri, 10 Jul 2020 19:07:38 +0200 Subject: arm: add (default) config for nanopi2 board Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01: - Configuration changed, mainly several "CONFIG_..." moved from s5p4418_nanopi2.h to s5p4418_nanopi2_defconfig and USB related configs removed because USB is not supported yet. - s5p4418_nanopi2.h: "CONFIG_" removed from several s5p4418/nanopi2 specific defines because the appropriate values do not need to be configurable. - pinctrl is supported now, therefore "CONFIG_PINCTRL=y" added to s5p4418_nanopi2_defconfig. Signed-off-by: Stefan Bosch --- MAINTAINERS | 17 +++ configs/s5p4418_nanopi2_defconfig | 147 ++++++++++++++++++++++ doc/README.s5p4418 | 63 ++++++++++ include/configs/s5p4418_nanopi2.h | 257 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 484 insertions(+) create mode 100644 configs/s5p4418_nanopi2_defconfig create mode 100644 doc/README.s5p4418 create mode 100644 include/configs/s5p4418_nanopi2.h (limited to 'doc') diff --git a/MAINTAINERS b/MAINTAINERS index d4cef2f0f34..eac3832fa20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -280,6 +280,23 @@ F: arch/arm/mach-at91/ F: board/atmel/ F: drivers/misc/microchip_flexcom.c +ARM NEXELL S5P4418 +M: Stefan Bosch +S: Maintained +F: arch/arm/cpu/armv7/s5p4418/ +F: arch/arm/dts/s5p4418* +F: arch/arm/mach-nexell/ +F: board/friendlyarm/ +F: configs/s5p4418_nanopi2_defconfig +F: doc/README.s5p4418 +F: drivers/gpio/nx_gpio.c +F: drivers/i2c/nx_i2c.c +F: drivers/mmc/nexell_dw_mmc_dm.c +F: drivers/pinctrl/nexell/ +F: drivers/video/nexell/ +F: drivers/video/nexell_display.c +F: include/configs/s5p4418_nanopi2.h + ARM OWL M: Manivannan Sadhasivam S: Maintained diff --git a/configs/s5p4418_nanopi2_defconfig b/configs/s5p4418_nanopi2_defconfig new file mode 100644 index 00000000000..c1cd08abf65 --- /dev/null +++ b/configs/s5p4418_nanopi2_defconfig @@ -0,0 +1,147 @@ +CONFIG_ARM=y +CONFIG_ARCH_NEXELL=y +CONFIG_ARCH_S5P4418=y +CONFIG_TARGET_NANOPI2=y +CONFIG_DEFAULT_DEVICE_TREE="s5p4418-nanopi2" +CONFIG_FIT=y + +CONFIG_SYS_MEMTEST_START=0x71000000 +CONFIG_SYS_MEMTEST_END=0xb0000000 + +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_I2C=y +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_GPIO=y +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_NET is not set + +# Default is CONFIG_NET=y, in this case: +# Loading Environment from MMC... ## Warning: Unknown environment variable type 'm' +# OK +# CONFIG_CMD_NET=y must be set to avoid this Warning. But then: +# Net: Net Initialization Skipped +# No ethernet found. +# If CONFIG_NET=n is set additionally warning at "make s5p4418_nanopi2_defconfig": +# arch/../configs/s5p4418_nanopi2_defconfig:24:warning: override: reassigning to symbol CMD_NET +# +# --> CONFIG_NET=n set only +CONFIG_NET=n + +# CONFIG_CMD_NFS is not set +CONFIG_CMD_FDISK=y +CONFIG_CMD_EXT4_IMG_WRITE=y +CONFIG_CMD_SD_RECOVERY=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y + +CONFIG_PINCTRL=y +CONFIG_DM_GPIO=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_NEXELL=y +CONFIG_DM_PMIC=y +CONFIG_DM_PMIC_AXP228=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_AXP228=y +CONFIG_DM_PWM=n + +CONFIG_DISPLAY=y +CONFIG_DM_VIDEO=y +CONFIG_SYS_CONSOLE_BG_COL=0xff +CONFIG_SYS_CONSOLE_FG_COL=0x00 +CONFIG_VIDEO_NX=y +CONFIG_VIDEO_NX_RGB=y +CONFIG_VIDEO_NX_LVDS=y +CONFIG_VIDEO_NX_HDMI=y +CONFIG_CMD_BMP=y + +## LCD backlight control +CONFIG_S5P4418_ONEWIRE=y +CONFIG_PWM_NX is not set + +CONFIG_REGEX=y +CONFIG_ERRNO_STR=y + +CONFIG_SYS_TEXT_BASE=0x74C00000 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_SYS_CACHELINE_SIZE=64 + +## System initialize options (board_init_f) +# board_init_f->init_sequence, call board_early_init_f +CONFIG_BOARD_LATE_INIT=y +# board_init_f->init_sequence, call print_cpuinfo +CONFIG_DISPLAY_CPUINFO=y +# board_init_f->init_sequence, call show_board_info +CONFIG_DISPLAY_BOARDINFO=y +# board_init_f, CONFIG_SYS_ICACHE_OFF +CONFIG_SYS_DCACHE_OFF=y +# board_init_r, call arch_misc_init +CONFIG_ARCH_MISC_INIT=y + +CONFIG_BOOTDELAY=1 +CONFIG_ZERO_BOOTDELAY_CHECK=y + +## U-Boot Environments +## refer to common/env_common.c + +# CONFIG_ENV_IS_IN_MMC must be set here and not in s5p4418_nanopi2.h +# otherwise CONFIG_ENV_IS_NOWHERE is set by env/Kconfig and environment +# (bootargs) are not loaded +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_OFFSET=0x2E0200 +CONFIG_ENV_SIZE=0x4000 +CONFIG_CMD_SAVEENV=y + +## Etc Command definition +# image info +CONFIG_CMD_IMI=y +# add command line history +CONFIG_CMDLINE_EDITING=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y +CONFIG_SUPPORT_RAW_INITRD=y +CONFIG_REVISION_TAG=y +CONFIG_CMD_BOOTZ=y + +## serial console configuration +CONFIG_CONS_INDEX=0 +CONFIG_BAUDRATE=115200 + +## SD/MMC +CONFIG_BOUNCE_BUFFER=y +CONFIG_GENERIC_MMC=y +CONFIG_MMC=y +CONFIG_MMC_DW=y +CONFIG_NEXELL_DWMMC=y +CONFIG_CMD_MMC=y +CONFIG_DM_MMC=y + +CONFIG_DOS_PARTITION=y +CONFIG_CMD_FAT=y +CONFIG_FS_FAT=y +CONFIG_FAT_WRITE=y + +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_FS_EXT4=y +CONFIG_EXT4_WRITE=y + +## OF_CONTROL +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_LIBFDT=y +CONFIG_OF_BOARD_SETUP=y + +## BOOTCOMMAND +CONFIG_ROOT_DEV=1 +CONFIG_BOOT_PART=1 +CONFIG_ROOT_PART=2 + +# necessary for if-cmd +CONFIG_HUSH_PARSER=y + +# set to 'n' to save memory +CONFIG_SYS_LONGHELP=y + +# For debugging (trace) of MMC-CMDs +CONFIG_MMC_TRACE=n diff --git a/doc/README.s5p4418 b/doc/README.s5p4418 new file mode 100644 index 00000000000..ac724d08a04 --- /dev/null +++ b/doc/README.s5p4418 @@ -0,0 +1,63 @@ + +Summary +======= + +This README is about U-Boot support for SAMSUNG's/NEXELL's ARM Cortex-A9 based +S5P4418 SoC. It is based on FriendlyARM's U-Boot v2016.01 for the NanoPi2 +(and other) boards [1]. + +Currently the following boards are supported: + +* FriendlyArm NanoPi2 [2] +* FriendlyArm NanoPC-T2 [3] + + +Build +===== + +* NanoPi2 and NanoPC-T2 + +make s5p4418_nanopi2_defconfig +make + + +Installation +============ + +- Download Official-ROMs-SDCard-20190718.7z from [4] (images files for android, + friendlyCore and LUbuntu) +- Use s5p4418-sd-lubuntu-desktop-xenial-4.4-armhf-20190718.img to make a SD-card +- Use dd in the directory where U-Boot has been built to update U-Boot: + (replace with the device used for the SD-card, e.g. sdc) + sudo dd seek=3841 if=u-boot.bin of=/dev/ +- Boot the board from this SD-card + +The source code for (the used?) LUbuntu 16.04 can be found at [5]. + + +Links +===== + +[1] FriendlyArm U-boot v2016.01: + +https://github.com/friendlyarm/u-boot/tree/nanopi2-v2016.01 + + +[2] NanoPi2: + +http://wiki.friendlyarm.com/wiki/index.php/NanoPi_2 + + +[3] NanoPC-T2: + +http://wiki.friendlyarm.com/wiki/index.php/NanoPC-T2 + + +[4] FriendlyArm image files for NanoPi2: + +http://download.friendlyarm.com//NanoPi2 + + +[5] FriendlyArm LUbuntu 16.04 Source Code for NanoPi2: + +https://github.com/friendlyarm/linux/tree/nanopi2-v4.4.y diff --git a/include/configs/s5p4418_nanopi2.h b/include/configs/s5p4418_nanopi2.h new file mode 100644 index 00000000000..da5b29a46ef --- /dev/null +++ b/include/configs/s5p4418_nanopi2.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * (C) Copyright 2016 Nexell + * Hyejung Kwon + * + * Copyright (C) 2019 Stefan Bosch + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#include +#include + +/*----------------------------------------------------------------------- + * System memory Configuration + */ +#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_MEM_SIZE 0x40000000 +#define CONFIG_SYS_SDRAM_BASE 0x71000000 + +/* + * "(CONFIG_SYS_MEM_SIZE - CONFIG_SYS_RESERVE_MEM_SIZE)" has been used in + * u-boot nanopi2-v2016.01. + * This is not working anymore because boot_fdt_add_mem_rsv_regions() in + * common/image-fdt.c has been extended: + * Also reserved-memory sections are marked as unusable. + * + * In friendlyArm Ubuntu 16.04 source arch/arm/boot/dts/s5p4418.dtsi: + * reserved-memory { + * #address-cells = <1>; + * #size-cells = <1>; + * ranges; + * + * secure_memory@b0000000 { + * reg = <0xB0000000 0x1000000>; + * nop-map; + * }; + * }; + * + * arch_lmb_reserve() of arch/arm/lib/bootm.c: + * "Allocate space for command line and board info - ... below the current + * stack pointer." + * --> Memory allocated would overlap with "secure_memory@b0000000" + * --> lmb_add_region(rgn, base==0xb0000000, size==0x1000000) fails, + * boot output: + * ... + * Kernel image @ 0x71080000 [ 0x000000 - 0x60e628 ] + * ## Flattened Device Tree blob at 7a000000 + * Booting using the fdt blob at 0x7a000000 + * ERROR: reserving fdt memory region failed (addr=b0000000 size=1000000) + * Using Device Tree in place at 7a000000, end 7a00fbf0 + * + * Starting kernel ... + * ... + */ +#define CONFIG_SYS_SDRAM_SIZE (0xb0000000 - CONFIG_SYS_SDRAM_BASE) + +#define CONFIG_SYS_MALLOC_LEN (32 * 1024 * 1024) + +#define BMP_LOAD_ADDR 0x78000000 + +/* kernel load address */ +#define CONFIG_SYS_LOAD_ADDR 0x71080000 +#define INITRD_START 0x79000000 +#define KERNEL_DTB_ADDR 0x7A000000 + +/*----------------------------------------------------------------------- + * High Level System Configuration + */ +/* Not used: not need IRQ/FIQ stuff */ +#undef CONFIG_USE_IRQ +/* decrementer freq: 1ms ticks */ +#define CONFIG_SYS_HZ 1000 + +/*----------------------------------------------------------------------- + * System initialize options (board_init_f) + */ +/* board_init_f->init_sequence, call arch_cpu_init */ +#define CONFIG_ARCH_CPU_INIT + +/*----------------------------------------------------------------------- + * Miscellaneous configurable options + */ +#ifdef CONFIG_SYS_PROMPT +#undef CONFIG_SYS_PROMPT +/* Monitor Command Prompt */ +#define CONFIG_SYS_PROMPT "nanopi2# " +#endif + +/* Console I/O Buffer Size */ +#define CONFIG_SYS_CBSIZE 1024 +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT) + 16) +/* max number of command args */ +#define CONFIG_SYS_MAXARGS 16 +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + +/*----------------------------------------------------------------------- + * allow to overwrite serial and ethaddr + */ +#define CONFIG_ENV_OVERWRITE + +#ifdef CONFIG_HUSH_PARSER +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " +#endif + +/*----------------------------------------------------------------------- + * Etc Command definition + */ +#undef CONFIG_BOOTM_NETBSD +#undef CONFIG_BOOTM_RTEMS + +/*----------------------------------------------------------------------- + * serial console configuration + */ +#define CONFIG_PL011_CLOCK 50000000 +#define CONFIG_PL01x_PORTS {(void *)PHY_BASEADDR_UART0, \ + (void *)PHY_BASEADDR_UART1, \ + (void *)PHY_BASEADDR_UART2, \ + (void *)PHY_BASEADDR_UART3} +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +/*----------------------------------------------------------------------- + * PLL + */ +#define CONFIG_SYS_PLLFIN 24000000UL + +/*----------------------------------------------------------------------- + * Timer + */ +#define CONFIG_TIMER_SYS_TICK_CH 0 + +/*----------------------------------------------------------------------- + * BACKLIGHT + */ +#ifndef CONFIG_S5P4418_ONEWIRE +#ifdef CONFIG_PWM_NX +/* fallback to pwm */ +#define BACKLIGHT_CH 0 +#define BACKLIGHT_DIV 0 +#define BACKLIGHT_INV 0 +#define BACKLIGHT_DUTY 50 +#define BACKLIGHT_HZ 1000 +#endif +#endif + +/*----------------------------------------------------------------------- + * SD/MMC + */ +#if defined(CONFIG_MMC) +/* eMMC = 0, SD-card = 2 */ +#define CONFIG_SYS_MMC_DEV 2 +#define CONFIG_SYS_MMC_ENV_DEV CONFIG_SYS_MMC_DEV +#endif + +/*----------------------------------------------------------------------- + * Default environment organization + */ +#if !defined(CONFIG_ENV_IS_IN_MMC) && !defined(CONFIG_ENV_IS_IN_NAND) && \ + !defined(CONFIG_ENV_IS_IN_FLASH) && !defined(CONFIG_ENV_IS_IN_EEPROM) + /* default: CONFIG_ENV_IS_NOWHERE */ + #define CONFIG_ENV_IS_NOWHERE + #define CONFIG_ENV_OFFSET 1024 + #define CONFIG_ENV_SIZE (4 * 1024) /* env size */ +#endif + +/*----------------------------------------------------------------------- + * VIDEO + */ + +#define CONFIG_VIDEO_LOGO + +#define CONFIG_SPLASH_SCREEN + +#ifdef CONFIG_VIDEO_LOGO + +#ifdef CONFIG_DM_VIDEO +#define CONFIG_BMP_24BPP +#endif + +#ifdef CONFIG_SPLASH_SCREEN +#define CONFIG_SPLASH_SOURCE 1 +#define CONFIG_SPLASH_SCREEN_ALIGN 1 +#define SPLASH_FILE logo.bmp +#endif + +#endif + +/*----------------------------------------------------------------------- + * ENV + */ +#define BLOADER_MMC \ + "ext4load mmc ${rootdev}:${bootpart} " + +#ifdef CONFIG_OF_BOARD_SETUP +#define EXTRA_ENV_DTB_RESERVE \ + "dtb_reserve=" \ + "if test -n \"$dtb_addr\"; then fdt addr $dtb_addr; fi\0" +#else +#define EXTRA_ENV_DTB_RESERVE \ + "dtb_reserve=" \ + "if test -n \"$fb_addr\"; then " \ + "fdt addr $dtb_addr;" \ + "fdt resize;" \ + "fdt mk /reserved-memory display_reserved;" \ + "fdt set /reserved-memory/display_reserved " \ + "reg <$fb_addr 0x800000>;" \ + "fi;\0" +#endif + +#ifdef CONFIG_SPLASH_SCREEN +#define EXTRA_ENV_BOOT_LOGO \ + "splashimage=" __stringify(BMP_LOAD_ADDR)"\0" \ + "splashfile=" __stringify(SPLASH_FILE)"\0" \ + "splashpos=m,m\0" \ + "fb_addr=\0" \ + EXTRA_ENV_DTB_RESERVE +#else + #define EXTRA_ENV_BOOT_LOGO EXTRA_ENV_DTB_RESERVE +#endif + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdt_high=0xffffffff\0" \ + "initrd_high=0xffffffff\0" \ + "rootdev=" __stringify(CONFIG_ROOT_DEV) "\0" \ + "rootpart=" __stringify(CONFIG_ROOT_PART) "\0" \ + "bootpart=" __stringify(CONFIG_BOOT_PART) "\0" \ + "kernel=zImage\0" \ + "loadaddr=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \ + "dtb_name=s5p4418-nanopi2-rev01.dtb\0" \ + "dtb_addr=" __stringify(KERNEL_DTB_ADDR) "\0" \ + "initrd_name=ramdisk.img\0" \ + "initrd_addr=" __stringify(INITRD_START) "\0" \ + "initrd_size=0x600000\0" \ + "load_dtb=" \ + BLOADER_MMC "${dtb_addr} ${dtb_name}; " \ + "run dtb_reserve\0" \ + "load_kernel=" \ + BLOADER_MMC "${loadaddr} ${kernel}\0" \ + "load_initrd=" \ + BLOADER_MMC "${initrd_addr} ${initrd_name}; " \ + "setenv initrd_size 0x${filesize}\0" \ + "mmcboot=" \ + "run load_kernel; run load_initrd; run load_dtb; " \ + "bootz ${loadaddr} ${initrd_addr}:${initrd_size} " \ + "${dtb_addr}\0" \ + "bootcmd=run mmcboot\0" \ + EXTRA_ENV_BOOT_LOGO + +#endif /* __CONFIG_H__ */ -- cgit v1.3.1