diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index 2de78d7c7..0d5428ded 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -31,5 +31,4 @@ obj-$(CONFIG_SHELL_NONE) += xload.o obj-$(CONFIG_MFD_TWL6030) += omap4_twl6030_mmc.o obj-$(CONFIG_OMAP4_USBBOOT) += omap4_rom_usb.o obj-$(CONFIG_CMD_BOOT_ORDER) += boot_order.o -obj-y += gpio.o obj-$(CONFIG_BAREBOX_UPDATE_AM33XX_SPI_NOR_MLO) += am33xx_bbu_spi_mlo.o diff --git a/arch/arm/mach-omap/gpmc.c b/arch/arm/mach-omap/gpmc.c index 72f7236cb..07eeae1ac 100644 --- a/arch/arm/mach-omap/gpmc.c +++ b/arch/arm/mach-omap/gpmc.c @@ -94,7 +94,10 @@ void gpmc_cs_config(char cs, struct gpmc_config *config) { void __iomem *reg = GPMC_REG(CONFIG1_0) + (cs * GPMC_CONFIG_CS_SIZE); unsigned char x = 0; - debug("gpmccs=0x%x cfg=0x%p\n", cs, config); + uint32_t config7; + + debug("%s: cs=%d base=0x%08x size=0x%08x\n", __func__, + cs, config->base, config->size); /* Disable the CS before reconfiguring */ writel(0x0, GPMC_REG(CONFIG7_0) + (cs * GPMC_CONFIG_CS_SIZE)); @@ -102,22 +105,22 @@ void gpmc_cs_config(char cs, struct gpmc_config *config) /* Write the CFG1-6 regs */ while (x < 6) { - debug("gpmccfg%d Reg:0x%p <-0x%08x\n", - x, reg, config->cfg[x]); + debug("gpmccfg%d Reg:0x%p <-0x%08x, old 0x%08x\n", + x, reg, config->cfg[x], readl(reg)); writel(config->cfg[x], reg); reg += GPMC_CONFIG_REG_OFF; x++; } - /* reg now points to CFG7 */ - debug("gpmccfg%d Reg:0x%p <-0x%08x\n", - x, reg, (0x1 << 6) | /* CS enable */ - ((config->size & 0xF) << 8) | /* Size */ - ((config->base >> 24) & 0x3F)); - writel((0x1 << 6) | /* CS enable */ + config7 = (0x1 << 6) | /* CS enable */ ((config->size & 0xF) << 8) | /* Size */ - ((config->base >> 24) & 0x3F), /* Address */ - reg); + ((config->base >> 24) & 0x3F); + + debug("gpmccfg%d Reg:0x%p <-0x%08x, old 0x%08x\n", + x, reg, config7, readl(reg)); + + writel(config7, reg); + mdelay(1); /* Settling time */ } EXPORT_SYMBOL(gpmc_cs_config); diff --git a/arch/arm/mach-omap/include/mach/am33xx-devices.h b/arch/arm/mach-omap/include/mach/am33xx-devices.h index 669198023..d2411a4fe 100644 --- a/arch/arm/mach-omap/include/mach/am33xx-devices.h +++ b/arch/arm/mach-omap/include/mach/am33xx-devices.h @@ -45,7 +45,7 @@ static inline struct device_d *am33xx_add_cpsw(struct cpsw_platform_data *cpsw_d static inline struct device_d *am33xx_add_spi(int id, resource_size_t start) { - return add_generic_device("omap3_spi", id, NULL, start + 0x100, SZ_4K - 0x100, + return add_generic_device("omap4-spi", id, NULL, start, SZ_4K, IORESOURCE_MEM, NULL); } diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h index 8d138ec9b..8839486fc 100644 --- a/arch/arm/mach-omap/include/mach/gpmc_nand.h +++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h @@ -59,6 +59,9 @@ struct gpmc_nand_platform_data { struct nand_ecclayout *oob; /** gpmc config for nand */ struct gpmc_config *nand_cfg; + + struct device_node *of_node; + struct device_node *elm_of_node; }; int omap_add_gpmc_nand_device(struct gpmc_nand_platform_data *pdata); diff --git a/arch/arm/mach-omap/omap_devices.c b/arch/arm/mach-omap/omap_devices.c index 30cfdd06b..9ed3dcf61 100644 --- a/arch/arm/mach-omap/omap_devices.c +++ b/arch/arm/mach-omap/omap_devices.c @@ -21,6 +21,6 @@ static struct NS16550_plat serial_plat = { struct device_d *omap_add_uart(int id, unsigned long base) { - return add_ns16550_device(id, base, 1024, - IORESOURCE_MEM_8BIT, &serial_plat); + return add_generic_device("omap-uart", id, NULL, base, 1024, + IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &serial_plat); } diff --git a/drivers/base/resource.c b/drivers/base/resource.c index 2985c78e3..71ae0fe3c 100644 --- a/drivers/base/resource.c +++ b/drivers/base/resource.c @@ -20,33 +20,67 @@ #include #include #include +#include -static struct device_d *alloc_device(const char* devname, int id, void *pdata) +struct device_d *device_alloc(const char *devname, int id) { struct device_d *dev; dev = xzalloc(sizeof(*dev)); strcpy(dev->name, devname); dev->id = id; - dev->platform_data = pdata; return dev; } +int device_add_data(struct device_d *dev, void *data, size_t size) +{ + free(dev->platform_data); + + if (data) + dev->platform_data = xmemdup(data, size); + else + dev->platform_data = NULL; + + return 0; +} + +int device_add_resources(struct device_d *dev, const struct resource *res, int num) +{ + dev->resource = xmemdup(res, sizeof(*res) * num); + dev->num_resources = num; + + return 0; +} + +int device_add_resource(struct device_d *dev, const char *resname, + resource_size_t start, resource_size_t size, unsigned int flags) +{ + struct resource res = { + .start = start, + .end = start + size - 1, + .flags = flags, + }; + + if (resname) + res.name = xstrdup(resname); + + return device_add_resources(dev, &res, 1); +} + struct device_d *add_generic_device(const char* devname, int id, const char *resname, resource_size_t start, resource_size_t size, unsigned int flags, void *pdata) { - struct resource *res; + struct device_d *dev; - res = xzalloc(sizeof(struct resource)); - if (resname) - res[0].name = xstrdup(resname); - res[0].start = start; - res[0].end = start + size - 1; - res[0].flags = flags; + dev = device_alloc(devname, id); + dev->platform_data = pdata; + device_add_resource(dev, resname, start, size, flags); - return add_generic_device_res(devname, id, res, 1, pdata); + platform_device_register(dev); + + return dev; } EXPORT_SYMBOL(add_generic_device); @@ -55,9 +89,9 @@ struct device_d *add_generic_device_res(const char* devname, int id, { struct device_d *dev; - dev = alloc_device(devname, id, pdata); - dev->resource = res; - dev->num_resources = nb; + dev = device_alloc(devname, id); + dev->platform_data = pdata; + device_add_resources(dev, res, nb); platform_device_register(dev); diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 5938d3f2d..b0d3c1fe9 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -4,4 +4,10 @@ config IMX_WEIM depends on ARCH_IMX bool "i.MX WEIM driver" +config BUS_OMAP_GPMC + depends on ARCH_OMAP + depends on OFDEVICE + depends on OMAP_GPMC + bool "TI OMAP/AM33xx GPMC support" + endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 42a8d4947..f1c5ac73c 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_IMX_WEIM) += imx-weim.o +obj-$(CONFIG_BUS_OMAP_GPMC) += omap-gpmc.o diff --git a/drivers/bus/omap-gpmc.c b/drivers/bus/omap-gpmc.c new file mode 100644 index 000000000..ad21af290 --- /dev/null +++ b/drivers/bus/omap-gpmc.c @@ -0,0 +1,523 @@ +/* + * OMAP GPMC driver. Based upon the corresponding Linux Code + * + * Copyright (C) 2013 Sascha Hauer, Pengutronix, + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPMC_CS_NUM 8 +#define GPMC_NR_WAITPINS 4 + +#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31) +#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30) +#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29) +#define GPMC_CONFIG1_READTYPE_SYNC (1 << 29) +#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28) +#define GPMC_CONFIG1_WRITETYPE_ASYNC (0 << 27) +#define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27) +#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25) +#define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23) +#define GPMC_CONFIG1_WAIT_READ_MON (1 << 22) +#define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21) +#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18) +#define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16) +#define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12) +#define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) +#define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10) +#define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) +#define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) +#define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4) +#define GPMC_CONFIG1_FCLK_DIV(val) (val & 3) +#define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1)) +#define GPMC_CONFIG1_FCLK_DIV3 (GPMC_CONFIG1_FCLK_DIV(2)) +#define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3)) +#define GPMC_CONFIG2_CSEXTRADELAY (1 << 7) +#define GPMC_CONFIG3_ADVEXTRADELAY (1 << 7) +#define GPMC_CONFIG4_OEEXTRADELAY (1 << 7) +#define GPMC_CONFIG4_WEEXTRADELAY (1 << 23) +#define GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN (1 << 6) +#define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN (1 << 7) +#define GPMC_CONFIG7_CSVALID (1 << 6) + +static unsigned int gpmc_cs_num = GPMC_CS_NUM; +static unsigned int gpmc_nr_waitpins; +static unsigned long gpmc_l3_clk = 100000000; /* This should be a proper clock */ +static void __iomem *gpmc_base; + +/* bool type time settings */ +struct gpmc_bool_timings { + bool cycle2cyclediffcsen; + bool cycle2cyclesamecsen; + bool we_extra_delay; + bool oe_extra_delay; + bool adv_extra_delay; + bool cs_extra_delay; + bool time_para_granularity; +}; + +/* + * Note that all values in this struct are in nanoseconds except sync_clk + * (which is in picoseconds), while the register values are in gpmc_fck cycles. + */ +struct gpmc_timings { + /* Minimum clock period for synchronous mode (in picoseconds) */ + u32 sync_clk; + + /* Chip-select signal timings corresponding to 1 */ + u32 cs_on; /* Assertion time */ + u32 cs_rd_off; /* Read deassertion time */ + u32 cs_wr_off; /* Write deassertion time */ + + /* ADV signal timings corresponding to GPMC_CONFIG3 */ + u32 adv_on; /* Assertion time */ + u32 adv_rd_off; /* Read deassertion time */ + u32 adv_wr_off; /* Write deassertion time */ + + /* WE signals timings corresponding to GPMC_CONFIG4 */ + u32 we_on; /* WE assertion time */ + u32 we_off; /* WE deassertion time */ + + /* OE signals timings corresponding to GPMC_CONFIG4 */ + u32 oe_on; /* OE assertion time */ + u32 oe_off; /* OE deassertion time */ + + /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */ + u32 page_burst_access; /* Multiple access word delay */ + u32 access; /* Start-cycle to first data valid delay */ + u32 rd_cycle; /* Total read cycle time */ + u32 wr_cycle; /* Total write cycle time */ + + u32 bus_turnaround; + u32 cycle2cycle_delay; + + u32 wait_monitoring; + u32 clk_activation; + + /* The following are only on OMAP3430 */ + u32 wr_access; /* WRACCESSTIME */ + u32 wr_data_mux_bus; /* WRDATAONADMUXBUS */ + + struct gpmc_bool_timings bool_timings; +}; + +struct gpmc_settings { + bool burst_wrap; /* enables wrap bursting */ + bool burst_read; /* enables read page/burst mode */ + bool burst_write; /* enables write page/burst mode */ + bool device_nand; /* device is NAND */ + bool sync_read; /* enables synchronous reads */ + bool sync_write; /* enables synchronous writes */ + bool wait_on_read; /* monitor wait on reads */ + bool wait_on_write; /* monitor wait on writes */ + u32 burst_len; /* page/burst length */ + u32 device_width; /* device bus width (8 or 16 bit) */ + u32 mux_add_data; /* multiplex address & data */ + u32 wait_pin; /* wait-pin to be used */ +}; + +struct imx_gpmc { + struct device_d *dev; + void __iomem *base; + struct imx_gpmc_devtype *devtype; +}; + +static void gpmc_cs_bool_timings(struct gpmc_config *gpmc_config, const struct gpmc_bool_timings *p) +{ + if (p->time_para_granularity) + gpmc_config->cfg[0] |= GPMC_CONFIG1_TIME_PARA_GRAN; + + if (p->cs_extra_delay) + gpmc_config->cfg[1] |= GPMC_CONFIG2_CSEXTRADELAY; + if (p->adv_extra_delay) + gpmc_config->cfg[2] |= GPMC_CONFIG3_ADVEXTRADELAY; + if (p->oe_extra_delay) + gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY; + if (p->we_extra_delay) + gpmc_config->cfg[3] |= GPMC_CONFIG4_OEEXTRADELAY; + if (p->cycle2cyclesamecsen) + gpmc_config->cfg[5] |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN; + if (p->cycle2cyclediffcsen) + gpmc_config->cfg[5] |= GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN; +} + +static unsigned long gpmc_get_fclk_period(void) +{ + unsigned long rate = gpmc_l3_clk; + + rate /= 1000; + rate = 1000000000 / rate; /* In picoseconds */ + + return rate; +} + +static unsigned int gpmc_ns_to_ticks(unsigned int time_ns) +{ + unsigned long tick_ps; + + /* Calculate in picosecs to yield more exact results */ + tick_ps = gpmc_get_fclk_period(); + + return (time_ns * 1000 + tick_ps - 1) / tick_ps; +} + +int gpmc_calc_divider(unsigned int sync_clk) +{ + int div; + u32 l; + + l = sync_clk + (gpmc_get_fclk_period() - 1); + div = l / gpmc_get_fclk_period(); + if (div > 4) + return -1; + if (div <= 0) + div = 1; + + return div; +} + +static int set_cfg(struct gpmc_config *gpmc_config, int reg, + int st_bit, int end_bit, int time) +{ + int ticks, mask, nr_bits; + + if (time == 0) + ticks = 0; + else + ticks = gpmc_ns_to_ticks(time); + + nr_bits = end_bit - st_bit + 1; + if (ticks >= 1 << nr_bits) + return -EINVAL; + + mask = (1 << nr_bits) - 1; + gpmc_config->cfg[reg] &= ~(mask << st_bit); + gpmc_config->cfg[reg] |= ticks << st_bit; + + return 0; +} + +static int gpmc_timings_to_config(struct gpmc_config *gpmc_config, const struct gpmc_timings *t) +{ + int div, ret = 0; + + div = gpmc_calc_divider(t->sync_clk); + if (div < 0) + return div; + + ret |= set_cfg(gpmc_config, 0, 18, 19, t->wait_monitoring); + ret |= set_cfg(gpmc_config, 0, 25, 26, t->clk_activation); + + ret |= set_cfg(gpmc_config, 1, 0, 3, t->cs_on); + ret |= set_cfg(gpmc_config, 1, 8, 12, t->cs_rd_off); + ret |= set_cfg(gpmc_config, 1, 16, 20, t->cs_wr_off); + + ret |= set_cfg(gpmc_config, 2, 0, 3, t->adv_on); + ret |= set_cfg(gpmc_config, 2, 8, 12, t->adv_rd_off); + ret |= set_cfg(gpmc_config, 2, 16, 20, t->adv_wr_off); + + ret |= set_cfg(gpmc_config, 3, 0, 3, t->oe_on); + ret |= set_cfg(gpmc_config, 3, 8, 12, t->oe_off); + ret |= set_cfg(gpmc_config, 3, 16, 19, t->we_on); + ret |= set_cfg(gpmc_config, 3, 24, 28, t->we_off); + + ret |= set_cfg(gpmc_config, 4, 0, 4, t->rd_cycle); + ret |= set_cfg(gpmc_config, 4, 8, 12, t->wr_cycle); + ret |= set_cfg(gpmc_config, 4, 16, 20, t->access); + + ret |= set_cfg(gpmc_config, 4, 24, 27, t->page_burst_access); + + ret |= set_cfg(gpmc_config, 5, 0, 3, t->bus_turnaround); + ret |= set_cfg(gpmc_config, 5, 8, 11, t->cycle2cycle_delay); + ret |= set_cfg(gpmc_config, 5, 16, 19, t->wr_data_mux_bus); + ret |= set_cfg(gpmc_config, 5, 24, 28, t->wr_access); + + if (ret) + return ret; + + gpmc_cs_bool_timings(gpmc_config, &t->bool_timings); + + return 0; +} + +/** + * gpmc_read_settings_dt - read gpmc settings from device-tree + * @np: pointer to device-tree node for a gpmc child device + * @p: pointer to gpmc settings structure + * + * Reads the GPMC settings for a GPMC child device from device-tree and + * stores them in the GPMC settings structure passed. The GPMC settings + * structure is initialised to zero by this function and so any + * previously stored settings will be cleared. + */ +static void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) +{ + memset(p, 0, sizeof(struct gpmc_settings)); + + p->sync_read = of_property_read_bool(np, "gpmc,sync-read"); + p->sync_write = of_property_read_bool(np, "gpmc,sync-write"); + of_property_read_u32(np, "gpmc,device-width", &p->device_width); + of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data); + + if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) { + p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap"); + p->burst_read = of_property_read_bool(np, "gpmc,burst-read"); + p->burst_write = of_property_read_bool(np, "gpmc,burst-write"); + if (!p->burst_read && !p->burst_write) + pr_warn("%s: page/burst-length set but not used!\n", + __func__); + } + + if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) { + p->wait_on_read = of_property_read_bool(np, + "gpmc,wait-on-read"); + p->wait_on_write = of_property_read_bool(np, + "gpmc,wait-on-write"); + if (!p->wait_on_read && !p->wait_on_write) + pr_warn("%s: read/write wait monitoring not enabled!\n", + __func__); + } +} + +static void gpmc_read_timings_dt(struct device_node *np, + struct gpmc_timings *gpmc_t) +{ + struct gpmc_bool_timings *p; + + if (!np || !gpmc_t) + return; + + memset(gpmc_t, 0, sizeof(*gpmc_t)); + + /* minimum clock period for syncronous mode */ + of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk); + + /* chip select timtings */ + of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on); + of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off); + of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off); + + /* ADV signal timings */ + of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on); + of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off); + of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off); + + /* WE signal timings */ + of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on); + of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off); + + /* OE signal timings */ + of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on); + of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off); + + /* access and cycle timings */ + of_property_read_u32(np, "gpmc,page-burst-access-ns", + &gpmc_t->page_burst_access); + of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access); + of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle); + of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle); + of_property_read_u32(np, "gpmc,bus-turnaround-ns", + &gpmc_t->bus_turnaround); + of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns", + &gpmc_t->cycle2cycle_delay); + of_property_read_u32(np, "gpmc,wait-monitoring-ns", + &gpmc_t->wait_monitoring); + of_property_read_u32(np, "gpmc,clk-activation-ns", + &gpmc_t->clk_activation); + + /* only applicable to OMAP3+ */ + of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access); + of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns", + &gpmc_t->wr_data_mux_bus); + + /* bool timing parameters */ + p = &gpmc_t->bool_timings; + + p->cycle2cyclediffcsen = + of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen"); + p->cycle2cyclesamecsen = + of_property_read_bool(np, "gpmc,cycle2cycle-samecsen"); + p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay"); + p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay"); + p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay"); + p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay"); + p->time_para_granularity = + of_property_read_bool(np, "gpmc,time-para-granularity"); +} + +struct dt_eccmode { + const char *name; + enum gpmc_ecc_mode mode; +}; + +static struct dt_eccmode modes[] = { + { + .name = "ham1", + .mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE, + }, { + .name = "sw", + .mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE, + }, { + .name = "hw", + .mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE, + }, { + .name = "hw-romcode", + .mode = OMAP_ECC_HAMMING_CODE_HW_ROMCODE, + }, { + .name = "bch4", + .mode = OMAP_ECC_BCH4_CODE_HW, + }, { + .name = "bch8", + .mode = OMAP_ECC_BCH8_CODE_HW, + }, { + .name = "bch8-romcode", + .mode = OMAP_ECC_BCH8_CODE_HW_ROMCODE, + }, +}; + +static int gpmc_probe_nand_child(struct device_d *dev, + struct device_node *child) +{ + u32 val; + const char *s; + struct gpmc_timings gpmc_t; + struct gpmc_nand_platform_data gpmc_nand_data = {}; + struct resource res; + struct gpmc_settings gpmc_settings = {}; + int ret, i; + + if (of_property_read_u32(child, "reg", &val) < 0) { + dev_err(dev, "%s has no 'reg' property\n", + child->full_name); + return -ENODEV; + } + + gpmc_base = dev_get_mem_region(dev, 0); + if (!gpmc_base) + return -ENODEV; + + gpmc_nand_data.cs = val; + gpmc_nand_data.of_node = child; + + /* Detect availability of ELM module */ + gpmc_nand_data.elm_of_node = of_parse_phandle(child, "ti,elm-id", 0); + if (gpmc_nand_data.elm_of_node == NULL) + gpmc_nand_data.elm_of_node = + of_parse_phandle(child, "elm_id", 0); + if (gpmc_nand_data.elm_of_node == NULL) + pr_warn("%s: ti,elm-id property not found\n", __func__); + + /* select ecc-scheme for NAND */ + if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) { + pr_err("%s: ti,nand-ecc-opt not found\n", __func__); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(modes); i++) { + struct dt_eccmode *mode = &modes[i]; + if (!strcmp(s, mode->name)) + gpmc_nand_data.ecc_mode = mode->mode; + } + + val = of_get_nand_bus_width(child); + if (val == 16) + gpmc_nand_data.device_width = NAND_BUSWIDTH_16; + + gpmc_read_timings_dt(child, &gpmc_t); + gpmc_read_settings_dt(child, &gpmc_settings); + + gpmc_nand_data.wait_mon_pin = gpmc_settings.wait_pin; + + gpmc_nand_data.nand_cfg = xzalloc(sizeof(*gpmc_nand_data.nand_cfg)); + + gpmc_timings_to_config(gpmc_nand_data.nand_cfg, &gpmc_t); + + gpmc_nand_data.nand_cfg->cfg[0] |= 2 << 10; + + ret = of_address_to_resource(child, 0, &res); + if (ret) + pr_err("of_address_to_resource failed\n"); + + gpmc_nand_data.nand_cfg->base = res.start; + gpmc_nand_data.nand_cfg->size = GPMC_SIZE_16M; + + gpmc_cs_config(gpmc_nand_data.cs, gpmc_nand_data.nand_cfg); + + dev = device_alloc("gpmc_nand", DEVICE_ID_DYNAMIC); + device_add_resource(dev, NULL, (resource_size_t)gpmc_base, SZ_4K, IORESOURCE_MEM); + device_add_data(dev, &gpmc_nand_data, sizeof(gpmc_nand_data)); + dev->device_node = child; + platform_device_register(dev); + + return 0; +} + +static int gpmc_probe(struct device_d *dev) +{ + struct device_node *child, *node = dev->device_node; + int ret; + + gpmc_generic_init(0x12); + + ret = of_property_read_u32(node, "gpmc,num-cs", + &gpmc_cs_num); + if (ret < 0) + return ret; + + ret = of_property_read_u32(node, "gpmc,num-waitpins", + &gpmc_nr_waitpins); + if (ret < 0) + return ret; + + for_each_child_of_node(node, child) { + + if (!child->name) + continue; + + if (!strncmp(child->name, "nand", 4)) + ret = gpmc_probe_nand_child(dev, child); + else + dev_warn(dev, "unhandled child %s\n", child->name); + + if (ret) + break; + } + + if (ret) + goto gpmc_err; + + return 0; + +gpmc_err: + return ret; +} + +static struct of_device_id gpmc_id_table[] = { + { .compatible = "ti,omap2420-gpmc" }, + { .compatible = "ti,omap2430-gpmc" }, + { .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */ + { .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */ + { .compatible = "ti,am3352-gpmc" }, /* am335x devices */ + { } +}; + +static struct driver_d gpmc_driver = { + .name = "omap-gpmc", + .of_compatible = DRV_OF_COMPAT(gpmc_id_table), + .probe = gpmc_probe, +}; +device_platform_driver(gpmc_driver); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 18d3135eb..7c426563e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -30,6 +30,9 @@ config GPIO_GENERIC_PLATFORM config GPIO_IMX def_bool ARCH_IMX +config GPIO_OMAP + def_bool ARCH_OMAP + config GPIO_ORION bool "GPIO support for Marvell Orion/MVEBU SoCs" depends on ARCH_MVEBU diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index dc9fb13d2..b7c536d21 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_IMX) += gpio-imx.o obj-$(CONFIG_GPIO_ORION) += gpio-orion.o +obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o diff --git a/arch/arm/mach-omap/gpio.c b/drivers/gpio/gpio-omap.c similarity index 81% rename from arch/arm/mach-omap/gpio.c rename to drivers/gpio/gpio-omap.c index 49ffbda50..e66a614f2 100644 --- a/arch/arm/mach-omap/gpio.c +++ b/drivers/gpio/gpio-omap.c @@ -48,6 +48,18 @@ struct omap_gpio_chip { struct gpio_chip chip; }; +struct omap_gpio_drvdata { + unsigned int regofs; +}; + +static struct omap_gpio_drvdata gpio_omap3_drvdata = { + .regofs = 0x0, +}; + +static struct omap_gpio_drvdata gpio_omap4_drvdata = { + .regofs = 0x100, +}; + static inline int omap_get_gpio_index(int gpio) { return gpio & 0x1f; @@ -129,11 +141,24 @@ static struct gpio_ops omap_gpio_ops = { static int omap_gpio_probe(struct device_d *dev) { struct omap_gpio_chip *omapgpio; + struct omap_gpio_drvdata *drvdata = NULL; + + dev_get_drvdata(dev, (unsigned long *)&drvdata); omapgpio = xzalloc(sizeof(*omapgpio)); omapgpio->base = dev_request_mem_region(dev, 0); + if (drvdata) + omapgpio->base += drvdata->regofs; + omapgpio->chip.ops = &omap_gpio_ops; - omapgpio->chip.base = dev->id * 32; + if (dev->id < 0) { + omapgpio->chip.base = of_alias_get_id(dev->device_node, "gpio"); + if (omapgpio->chip.base < 0) + return omapgpio->chip.base; + omapgpio->chip.base *= 32; + } else { + omapgpio->chip.base = dev->id * 32; + } omapgpio->chip.ngpio = 32; omapgpio->chip.dev = dev; gpiochip_add(&omapgpio->chip); @@ -144,9 +169,21 @@ static int omap_gpio_probe(struct device_d *dev) return 0; } +static __maybe_unused struct of_device_id omap_gpio_dt_ids[] = { + { + .compatible = "ti,omap4-gpio", + .data = (unsigned long)&gpio_omap4_drvdata, + }, { + .compatible = "ti,omap3-gpio", + .data = (unsigned long)&gpio_omap3_drvdata, + }, { + } +}; + static struct driver_d omap_gpio_driver = { .name = "omap-gpio", .probe = omap_gpio_probe, + .of_compatible = DRV_OF_COMPAT(omap_gpio_dt_ids), }; static int omap_gpio_add(void) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c45af92ab..f7108c260 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -151,6 +151,7 @@ struct omap_i2c_struct { u8 reg_shift; struct omap_i2c_driver_data *data; struct resource *ioarea; + u32 fclk_rate; u32 speed; /* Speed of bus in Khz */ u16 scheme; u16 cmd_err; @@ -271,6 +272,11 @@ static struct omap_i2c_driver_data am33xx_data = { .fclk_rate = 48000, }; +static struct omap_i2c_driver_data omap4_of_data = { + .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE, + .fclk_rate = 0, +}; + static inline void omap_i2c_write_reg(struct omap_i2c_struct *i2c_omap, int reg, u16 val) { @@ -415,7 +421,7 @@ static int omap_i2c_init(struct omap_i2c_struct *i2c_omap) internal_clk = 4000; /* Compute prescaler divisor */ - psc = i2c_data->fclk_rate / internal_clk; + psc = i2c_omap->fclk_rate / internal_clk; psc = psc - 1; /* If configured for High Speed */ @@ -1074,6 +1080,12 @@ i2c_omap_probe(struct device_d *pdev) i2c_omap->b_hw = 1; /* Enable hardware fixes */ } + i2c_omap->fclk_rate = i2c_data->fclk_rate; + + if (!i2c_omap->fclk_rate) + of_property_read_u32(pdev->device_node, "clock-frequency", + &i2c_omap->fclk_rate); + /* reset ASAP, clearing any IRQs */ omap_i2c_init(i2c_omap); @@ -1085,6 +1097,7 @@ i2c_omap_probe(struct device_d *pdev) i2c_omap->adapter.master_xfer = omap_i2c_xfer, i2c_omap->adapter.nr = pdev->id; i2c_omap->adapter.dev.parent = pdev; + i2c_omap->adapter.dev.device_node = pdev->device_node; /* i2c device drivers may be active on return from add_adapter() */ r = i2c_add_numbered_adapter(&i2c_omap->adapter); @@ -1119,10 +1132,23 @@ static struct platform_device_id omap_i2c_ids[] = { }, }; +static __maybe_unused struct of_device_id omap_spi_dt_ids[] = { + { + .compatible = "ti,omap3-i2c", + .data = (unsigned long)&omap3_data, + }, { + .compatible = "ti,omap4-i2c", + .data = (unsigned long)&omap4_of_data, + }, { + /* sentinel */ + } +}; + static struct driver_d omap_i2c_driver = { .probe = i2c_omap_probe, .name = DRIVER_NAME, .id_table = omap_i2c_ids, + .of_compatible = DRV_OF_COMPAT(omap_spi_dt_ids), }; device_platform_driver(omap_i2c_driver); diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c index 357d99a0d..9cce91692 100644 --- a/drivers/mci/omap_hsmmc.c +++ b/drivers/mci/omap_hsmmc.c @@ -646,9 +646,22 @@ static struct platform_device_id omap_mmc_ids[] = { }, }; +static __maybe_unused struct of_device_id omap_mmc_dt_ids[] = { + { + .compatible = "ti,omap3-hsmmc", + .data = (unsigned long)&omap3_data, + }, { + .compatible = "ti,omap4-hsmmc", + .data = (unsigned long)&omap4_data, + }, { + /* sentinel */ + } +}; + static struct driver_d omap_mmc_driver = { .name = "omap-hsmmc", .probe = omap_mmc_probe, .id_table = omap_mmc_ids, + .of_compatible = DRV_OF_COMPAT(omap_mmc_dt_ids), }; device_platform_driver(omap_mmc_driver); diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index 448e7b979..3053a8e89 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -90,7 +90,7 @@ int omap_gpmc_decode_bch(int select_4_8, unsigned char *ecc, unsigned int *err_loc); -static char *ecc_mode_strings[] = { +static const char *ecc_mode_strings[] = { "software", "hamming_hw_romcode", "bch4_hw", @@ -861,29 +861,11 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo, return 0; } -static int omap_gpmc_eccmode_set(struct device_d *dev, struct param_d *param, const char *val) +static int omap_gpmc_eccmode_set(struct param_d *param, void *priv) { - struct gpmc_nand_info *oinfo = dev->priv; - int i; + struct gpmc_nand_info *oinfo = priv; - if (!val) - return 0; - - for (i = 0; i < ARRAY_SIZE(ecc_mode_strings); i++) - if (!strcmp(ecc_mode_strings[i], val)) - break; - - if (i == ARRAY_SIZE(ecc_mode_strings)) { - dev_err(dev, "invalid ecc mode '%s'\n", val); - printf("valid modes:\n"); - for (i = 0; i < ARRAY_SIZE(ecc_mode_strings); i++) - printf("%s\n", ecc_mode_strings[i]); - return -EINVAL; - } - - dev_param_set_generic(dev, param, ecc_mode_strings[i]); - - return omap_gpmc_eccmode(oinfo, i); + return omap_gpmc_eccmode(oinfo, oinfo->ecc_mode); } static int gpmc_set_buswidth(struct nand_chip *chip, int buswidth) @@ -1062,11 +1044,13 @@ static int gpmc_nand_probe(struct device_d *pdev) nand->options |= NAND_SKIP_BBTSCAN; - dev_add_param(pdev, "eccmode", omap_gpmc_eccmode_set, NULL, 0); - dev_set_param(pdev, "eccmode", ecc_mode_strings[pdata->ecc_mode]); + oinfo->ecc_mode = pdata->ecc_mode; - if (! IS_ENABLED(CONFIG_PARAMETER)) - omap_gpmc_eccmode(oinfo, pdata->ecc_mode); + dev_add_param_enum(pdev, "eccmode", + omap_gpmc_eccmode_set, NULL, (int *)&oinfo->ecc_mode, + ecc_mode_strings, ARRAY_SIZE(ecc_mode_strings), oinfo); + + omap_gpmc_eccmode(oinfo, oinfo->ecc_mode); /* We are all set to register with the system now! */ err = add_mtd_nand_device(minfo, "nand"); diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index e51a8b1b6..5e68e1be6 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -27,6 +27,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -175,7 +179,10 @@ struct cpsw_slave { struct cpsw_sliver_regs *sliver; int slave_num; u32 mac_control; - struct cpsw_slave_data *data; + int phy_id; + phy_interface_t phy_if; + struct eth_device edev; + struct cpsw_priv *cpsw; }; struct cpdma_desc { @@ -196,7 +203,6 @@ struct cpdma_chan { struct cpsw_priv { struct device_d *dev; - struct eth_device edev; struct mii_bus miibus; u32 version; @@ -223,12 +229,6 @@ struct cpsw_priv { struct cpdma_chan rx_chan, tx_chan; struct cpsw_slave *slaves; -#define for_each_slave(priv, func, arg...) \ - do { \ - int idx; \ - for (idx = 0; idx < (priv)->num_slaves; idx++) \ - (func)((priv)->slaves + idx, ##arg); \ - } while (0) }; static int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) @@ -537,19 +537,10 @@ static inline void soft_reset(struct cpsw_priv *priv, void *reg) ((mac)[2] << 16) | ((mac)[3] << 24)) #define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) -static void cpsw_set_slave_mac(struct cpsw_slave *slave, - struct cpsw_priv *priv, - unsigned char *mac) -{ - dev_dbg(priv->dev, "* %s\n", __func__); - - writel(mac_hi(mac), &slave->regs->sa_hi); - writel(mac_lo(mac), &slave->regs->sa_lo); -} - static int cpsw_get_hwaddr(struct eth_device *edev, unsigned char *mac) { - struct cpsw_priv *priv = edev->priv; + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; dev_dbg(priv->dev, "* %s\n", __func__); @@ -558,13 +549,15 @@ static int cpsw_get_hwaddr(struct eth_device *edev, unsigned char *mac) static int cpsw_set_hwaddr(struct eth_device *edev, unsigned char *mac) { - struct cpsw_priv *priv = edev->priv; + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; dev_dbg(priv->dev, "* %s\n", __func__); memcpy(&priv->mac_addr, mac, sizeof(priv->mac_addr)); - for_each_slave(priv, cpsw_set_slave_mac, priv, mac); + writel(mac_hi(mac), &slave->regs->sa_hi); + writel(mac_lo(mac), &slave->regs->sa_lo); return 0; } @@ -572,7 +565,7 @@ static int cpsw_set_hwaddr(struct eth_device *edev, unsigned char *mac) static void cpsw_slave_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv, int *link) { - struct phy_device *phydev = priv->edev.phydev; + struct phy_device *phydev = slave->edev.phydev; u32 mac_control = 0; dev_dbg(priv->dev, "* %s\n", __func__); @@ -612,22 +605,25 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, slave->mac_control = mac_control; } -static int cpsw_update_link(struct cpsw_priv *priv) +static int cpsw_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv) { int link = 0; dev_dbg(priv->dev, "* %s\n", __func__); - for_each_slave(priv, cpsw_slave_update_link, priv, &link); + cpsw_slave_update_link(slave, priv, &link); + return link; } -static void cpsw_adjust_link(struct eth_device *edev) { - struct cpsw_priv *priv = edev->priv; +static void cpsw_adjust_link(struct eth_device *edev) +{ + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; dev_dbg(priv->dev, "* %s\n", __func__); - cpsw_update_link(priv); + cpsw_update_link(slave, priv); } static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) @@ -764,14 +760,14 @@ static int cpsw_init(struct eth_device *edev) static int cpsw_open(struct eth_device *edev) { - struct cpsw_priv *priv = edev->priv; - struct cpsw_slave_data *slave_data = priv->data.slave_data; + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; int i, ret; dev_dbg(priv->dev, "* %s\n", __func__); - ret = phy_device_connect(edev, &priv->miibus, slave_data[0].phy_id, - cpsw_adjust_link, 0, slave_data[0].phy_if); + ret = phy_device_connect(edev, &priv->miibus, slave->phy_id, + cpsw_adjust_link, 0, slave->phy_if); if (ret) return ret; @@ -800,9 +796,8 @@ static int cpsw_open(struct eth_device *edev) ALE_SECURE); cpsw_ale_add_mcast(priv, ethbdaddr, 1 << priv->host_port); - for_each_slave(priv, cpsw_slave_init, priv); - - cpsw_update_link(priv); + cpsw_slave_init(&priv->slaves[0], priv); + cpsw_update_link(&priv->slaves[0], priv); /* init descriptor pool */ for (i = 0; i < NUM_DESCS; i++) { @@ -850,9 +845,10 @@ static int cpsw_open(struct eth_device *edev) return 0; } -static void cpsw_halt(struct eth_device *dev) +static void cpsw_halt(struct eth_device *edev) { - struct cpsw_priv *priv = dev->priv; + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; writel(0, priv->dma_regs + CPDMA_TXCONTROL); writel(0, priv->dma_regs + CPDMA_RXCONTROL); @@ -864,9 +860,10 @@ static void cpsw_halt(struct eth_device *dev) soft_reset(priv, priv->dma_regs + CPDMA_SOFTRESET); } -static int cpsw_send(struct eth_device *dev, void *packet, int length) +static int cpsw_send(struct eth_device *edev, void *packet, int length) { - struct cpsw_priv *priv = dev->priv; + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; void *buffer; int ret, len; @@ -884,9 +881,10 @@ static int cpsw_send(struct eth_device *dev, void *packet, int length) return ret; } -static int cpsw_recv(struct eth_device *dev) +static int cpsw_recv(struct eth_device *edev) { - struct cpsw_priv *priv = dev->priv; + struct cpsw_slave *slave = edev->priv; + struct cpsw_priv *priv = slave->cpsw; void *buffer; int len; @@ -899,18 +897,39 @@ static int cpsw_recv(struct eth_device *dev) return 0; } -static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, +static void cpsw_slave_init_data(struct cpsw_slave *slave, int slave_num, + struct cpsw_priv *priv) +{ + struct cpsw_slave_data *data = priv->data.slave_data + slave_num; + + slave->phy_id = data->phy_id; + slave->phy_if = data->phy_if; +} + +static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, struct cpsw_priv *priv) { void *regs = priv->regs; - struct cpsw_slave_data *data = priv->data.slave_data + slave_num; + struct eth_device *edev = &slave->edev; dev_dbg(priv->dev, "* %s\n", __func__); slave->slave_num = slave_num; - slave->data = data; slave->regs = regs + priv->slave_ofs + priv->slave_size * slave_num; slave->sliver = regs + priv->sliver_ofs + SLIVER_SIZE * slave_num; + slave->cpsw = priv; + + edev->priv = slave; + edev->init = cpsw_init; + edev->open = cpsw_open; + edev->halt = cpsw_halt; + edev->send = cpsw_send; + edev->recv = cpsw_recv; + edev->get_ethaddr = cpsw_get_hwaddr; + edev->set_ethaddr = cpsw_set_hwaddr; + edev->parent = priv->dev; + + return eth_register(edev); } struct cpsw_data { @@ -948,15 +967,139 @@ static struct cpsw_data cpsw2_data = { .cppi_ram_ofs = 0x2000, }; +static void __iomem *phy_sel_addr; +static bool rmii_clock_external; + +static int cpsw_phy_sel_init(struct cpsw_priv *priv, struct device_node *np) +{ + const void *reg; + unsigned long addr; + + reg = of_get_property(np, "reg", NULL); + if (!reg) + return -EINVAL; + + addr = of_translate_address(np, reg); + + phy_sel_addr = (void *)addr; + + if (of_property_read_bool(np, "rmii-clock-ext")) + rmii_clock_external = true; + + return 0; +} + +/* AM33xx SoC specific definitions for the CONTROL port */ +#define AM33XX_GMII_SEL_MODE_MII 0 +#define AM33XX_GMII_SEL_MODE_RMII 1 +#define AM33XX_GMII_SEL_MODE_RGMII 2 + +#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7) +#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6) + +static void cpsw_gmii_sel_am335x(struct cpsw_slave *slave) +{ + u32 reg; + u32 mask; + u32 mode = 0; + + reg = readl(phy_sel_addr); + + switch (slave->phy_if) { + case PHY_INTERFACE_MODE_RMII: + mode = AM33XX_GMII_SEL_MODE_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + mode = AM33XX_GMII_SEL_MODE_RGMII; + break; + + case PHY_INTERFACE_MODE_MII: + default: + mode = AM33XX_GMII_SEL_MODE_MII; + break; + }; + + mask = 0x3 << (slave->slave_num * 2) | BIT(slave->slave_num + 6); + mode <<= slave->slave_num * 2; + + if (rmii_clock_external) { + if (slave->slave_num == 0) + mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN; + else + mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN; + } + + reg &= ~mask; + reg |= mode; + + writel(reg, phy_sel_addr); +} + +static int cpsw_probe_dt(struct cpsw_priv *priv) +{ + struct device_d *dev = priv->dev; + struct device_node *np = dev->device_node, *child; + int ret, i = 0; + + ret = of_property_read_u32(np, "slaves", &priv->num_slaves); + if (ret) + return ret; + + priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves); + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, "ti,am3352-cpsw-phy-sel")) { + ret = cpsw_phy_sel_init(priv, child); + if (ret) + return ret; + } + + if (of_device_is_compatible(child, "ti,davinci_mdio")) { + ret = of_pinctrl_select_state_default(child); + if (ret) + return ret; + } + + if (!strncmp(child->name, "slave", 5)) { + struct cpsw_slave *slave = &priv->slaves[i]; + uint32_t phy_id[2]; + + ret = of_property_read_u32_array(child, "phy_id", phy_id, 2); + if (ret) + return ret; + + slave->phy_id = phy_id[1]; + slave->phy_if = of_get_phy_mode(child); + + i++; + } + } + + for (i = 0; i < 2; i++) { + struct cpsw_slave *slave = &priv->slaves[i]; + + cpsw_gmii_sel_am335x(slave); + } + + /* Only one slave supported by this driver */ + priv->num_slaves = 1; + + return 0; +} + int cpsw_probe(struct device_d *dev) { struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data; struct cpsw_priv *priv; void __iomem *regs; - struct eth_device *edev; uint64_t start; uint32_t phy_mask; struct cpsw_data *cpsw_data; + int ret; dev_dbg(dev, "* %s\n", __func__); @@ -964,13 +1107,20 @@ int cpsw_probe(struct device_d *dev) priv = xzalloc(sizeof(*priv)); priv->dev = dev; - priv->data = *data; - priv->channels = 8; - priv->num_slaves = data->num_slaves; - priv->ale_entries = 1024; - edev = &priv->edev; - priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves); + if (dev->device_node) { + ret = cpsw_probe_dt(priv); + if (ret) + goto out; + } else { + priv->data = *data; + priv->num_slaves = data->num_slaves; + priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves); + cpsw_slave_init_data(&priv->slaves[0], 0, priv); + } + + priv->channels = 8; + priv->ale_entries = 1024; priv->host_port = 0; priv->regs = regs; @@ -985,7 +1135,8 @@ int cpsw_probe(struct device_d *dev) cpsw_data = &cpsw2_data; break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } priv->descs = regs + cpsw_data->cppi_ram_ofs; @@ -999,18 +1150,6 @@ int cpsw_probe(struct device_d *dev) priv->slave_size = cpsw_data->slave_size; priv->sliver_ofs = cpsw_data->sliver_ofs; - for_each_slave(priv, cpsw_slave_setup, idx, priv); - - edev->priv = priv; - edev->init = cpsw_init; - edev->open = cpsw_open; - edev->halt = cpsw_halt; - edev->send = cpsw_send; - edev->recv = cpsw_recv; - edev->get_ethaddr = cpsw_get_hwaddr; - edev->set_ethaddr = cpsw_set_hwaddr; - edev->parent = dev; - priv->miibus.read = cpsw_mdio_read; priv->miibus.write = cpsw_mdio_write; priv->miibus.priv = priv; @@ -1052,13 +1191,29 @@ int cpsw_probe(struct device_d *dev) mdiobus_register(&priv->miibus); - eth_register(edev); + ret = cpsw_slave_setup(&priv->slaves[0], 0, priv); + if (ret) + goto out; return 0; +out: + free(priv->slaves); + free(priv); + + return ret; } +static __maybe_unused struct of_device_id cpsw_dt_ids[] = { + { + .compatible = "ti,cpsw", + }, { + /* sentinel */ + } +}; + static struct driver_d cpsw_driver = { .name = "cpsw", .probe = cpsw_probe, + .of_compatible = DRV_OF_COMPAT(cpsw_dt_ids), }; device_platform_driver(cpsw_driver); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 58397a0ac..825758692 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -23,6 +23,9 @@ config PINCTRL_IMX_IOMUX_V3 help This iomux controller is found on i.MX25,35,51,53,6. +config PINCTRL_SINGLE + bool "pinctrl single" + config PINCTRL_TEGRA20 select PINCTRL bool diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 169ed184c..b3b0fa9c5 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V1) += imx-iomux-v1.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V2) += imx-iomux-v2.o obj-$(CONFIG_PINCTRL_IMX_IOMUX_V3) += imx-iomux-v3.o +obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c new file mode 100644 index 000000000..5c60c70b1 --- /dev/null +++ b/drivers/pinctrl/pinctrl-single.c @@ -0,0 +1,166 @@ +/* + * pinctrl-single - Generic device tree based pinctrl driver for one + * register per pin type pinmux controllers + * + * Copyright (c) 2013 Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +struct pinctrl_single { + void __iomem *base; + struct pinctrl_device pinctrl; + unsigned (*read)(void __iomem *reg); + void (*write)(unsigned val, void __iomem *reg); + unsigned width; +}; + +static unsigned __maybe_unused pcs_readb(void __iomem *reg) +{ + return readb(reg); +} + +static unsigned __maybe_unused pcs_readw(void __iomem *reg) +{ + return readw(reg); +} + +static unsigned __maybe_unused pcs_readl(void __iomem *reg) +{ + return readl(reg); +} + +static void __maybe_unused pcs_writeb(unsigned val, void __iomem *reg) +{ + writeb(val, reg); +} + +static void __maybe_unused pcs_writew(unsigned val, void __iomem *reg) +{ + writew(val, reg); +} + +static void __maybe_unused pcs_writel(unsigned val, void __iomem *reg) +{ + writel(val, reg); +} + +static int pcs_set_state(struct pinctrl_device *pdev, struct device_node *np) +{ + struct pinctrl_single *pcs = container_of(pdev, struct pinctrl_single, pinctrl); + unsigned size = 0, index = 0; + const __be32 *mux; + + dev_dbg(pcs->pinctrl.dev, "set state: %s\n", np->full_name); + + mux = of_get_property(np, "pinctrl-single,pins", &size); + + size /= sizeof(*mux); /* Number of elements in array */ + + if (!mux || !size || (size & 1)) { + dev_err(pcs->pinctrl.dev, "bad data for mux %s\n", + np->full_name); + return -EINVAL; + } + + while (index < size) { + unsigned offset, val; + + offset = be32_to_cpup(mux + index++); + val = be32_to_cpup(mux + index++); + + pcs->write(val, pcs->base + offset); + } + + return 0; +} + +static struct pinctrl_ops pcs_ops = { + .set_state = pcs_set_state, +}; + +static int pcs_probe(struct device_d *dev) +{ + struct pinctrl_single *pcs; + struct device_node *np = dev->device_node; + int ret = 0; + + pcs = xzalloc(sizeof(*pcs)); + pcs->base = dev_request_mem_region(dev, 0); + pcs->pinctrl.dev = dev; + pcs->pinctrl.ops = &pcs_ops; + + ret = of_property_read_u32(np, "pinctrl-single,register-width", + &pcs->width); + if (ret) { + dev_dbg(dev, "no pinctrl-single,register-width property\n"); + goto out; + } + + switch (pcs->width) { + case 8: + pcs->read = pcs_readb; + pcs->write = pcs_writeb; + break; + case 16: + pcs->read = pcs_readw; + pcs->write = pcs_writew; + break; + case 32: + pcs->read = pcs_readl; + pcs->write = pcs_writel; + break; + default: + ret = -EINVAL; + dev_dbg(dev, "invalid register width: %d\n", pcs->width); + goto out; + } + + ret = pinctrl_register(&pcs->pinctrl); + if (ret) + goto out; + + return 0; + +out: + free(pcs); + + return ret; +} + +static __maybe_unused struct of_device_id pcs_dt_ids[] = { + { + .compatible = "pinctrl-single", + }, { + /* sentinel */ + } +}; + +static struct driver_d pcs_driver = { + .name = "pinctrl-single", + .probe = pcs_probe, + .of_compatible = DRV_OF_COMPAT(pcs_dt_ids), +}; + +static int pcs_init(void) +{ + return platform_driver_register(&pcs_driver); +} +postcore_initcall(pcs_init); diff --git a/drivers/pinctrl/pinctrl.c b/drivers/pinctrl/pinctrl.c index 7f76d5a68..8963ac75c 100644 --- a/drivers/pinctrl/pinctrl.c +++ b/drivers/pinctrl/pinctrl.c @@ -51,7 +51,7 @@ static int pinctrl_config_one(struct device_node *np) return pdev->ops->set_state(pdev, np); } -int pinctrl_select_state(struct device_d *dev, const char *name) +int of_pinctrl_select_state(struct device_node *np, const char *name) { int state, ret; char *propname; @@ -59,13 +59,9 @@ int pinctrl_select_state(struct device_d *dev, const char *name) const __be32 *list; int size, config; phandle phandle; - struct device_node *np_config, *np; + struct device_node *np_config; const char *statename; - np = dev->device_node; - if (!np) - return 0; - if (!of_find_property(np, "pinctrl-0", NULL)) return 0; @@ -127,6 +123,22 @@ err: return ret; } +int of_pinctrl_select_state_default(struct device_node *np) +{ + return of_pinctrl_select_state(np, "default"); +} + +int pinctrl_select_state(struct device_d *dev, const char *name) +{ + struct device_node *np; + + np = dev->device_node; + if (!np) + return 0; + + return of_pinctrl_select_state(np, name); +} + int pinctrl_select_state_default(struct device_d *dev) { return pinctrl_select_state(dev, "default"); diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index d3a5a8176..a8487b0ed 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -55,6 +55,10 @@ static inline struct ns16550_priv *to_ns16550_priv(struct console_device *cdev) return container_of(cdev, struct ns16550_priv, cdev); } +struct ns16550_drvdata { + void (*init_port)(struct console_device *cdev); +}; + /** * @brief read register * @@ -178,14 +182,16 @@ static void ns16550_serial_init_port(struct console_device *cdev) /* initializing the device for the first time */ ns16550_write(cdev, 0x00, lcr); /* select ier reg */ ns16550_write(cdev, 0x00, ier); +} -#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS - ns16550_write(cdev, 0x07, mdr1); /* Disable */ -#endif +#define omap_mdr1 8 -#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS - ns16550_write(cdev, 0x00, mdr1); -#endif +static void ns16550_omap_init_port(struct console_device *cdev) +{ + ns16550_serial_init_port(cdev); + + ns16550_write(cdev, 0x07, omap_mdr1); /* Disable */ + ns16550_write(cdev, 0x00, omap_mdr1); } /*********** Exposed Functions **********************************/ @@ -239,6 +245,14 @@ static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv) of_property_read_u32(np, "reg-shift", &priv->plat.shift); } +static struct ns16550_drvdata ns16550_drvdata = { + .init_port = ns16550_serial_init_port, +}; + +static __maybe_unused struct ns16550_drvdata omap_drvdata = { + .init_port = ns16550_omap_init_port, +}; + /** * @brief Probe entry point -called on the first match for device * @@ -253,8 +267,13 @@ static int ns16550_probe(struct device_d *dev) struct ns16550_priv *priv; struct console_device *cdev; struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data; + struct ns16550_drvdata *devtype; int ret; + ret = dev_get_drvdata(dev, (unsigned long *)&devtype); + if (ret) + devtype = &ns16550_drvdata; + dev->priv = dev_request_mem_region(dev, 0); priv = xzalloc(sizeof(*priv)); @@ -294,7 +313,7 @@ static int ns16550_probe(struct device_d *dev) cdev->getc = ns16550_getc; cdev->setbrg = ns16550_setbaudrate; - ns16550_serial_init_port(cdev); + devtype->init_port(cdev); return console_register(cdev); @@ -307,8 +326,32 @@ err: static struct of_device_id ns16550_serial_dt_ids[] = { { .compatible = "ns16550a", - },{ + .data = (unsigned long)&ns16550_drvdata, + }, { .compatible = "snps,dw-apb-uart", + .data = (unsigned long)&ns16550_drvdata, + }, +#if IS_ENABLED(CONFIG_ARCH_OMAP) + { + .compatible = "ti,omap2-uart", + .data = (unsigned long)&omap_drvdata, + }, { + .compatible = "ti,omap3-uart", + .data = (unsigned long)&omap_drvdata, + }, { + .compatible = "ti,omap4-uart", + .data = (unsigned long)&omap_drvdata, + }, +#endif + { + /* sentinel */ + }, +}; + +static __maybe_unused struct platform_device_id ns16550_serial_ids[] = { + { + .name = "omap-uart", + .driver_data = (unsigned long)&omap_drvdata, }, { /* sentinel */ }, @@ -321,5 +364,8 @@ static struct driver_d ns16550_serial_driver = { .name = "ns16550_serial", .probe = ns16550_probe, .of_compatible = DRV_OF_COMPAT(ns16550_serial_dt_ids), +#if IS_ENABLED(CONFIG_ARCH_OMAP) + .id_table = ns16550_serial_ids, +#endif }; console_platform_driver(ns16550_serial_driver); diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h index db8fe6499..c37d63ca9 100644 --- a/drivers/serial/serial_ns16550.h +++ b/drivers/serial/serial_ns16550.h @@ -40,10 +40,6 @@ #define lsr 5 #define msr 6 #define scr 7 -#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS -#define mdr1 8 -#define osc_12m_sel 9 -#endif #define thr rbr #define iir fcr diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 5c8cc8882..073a98f0c 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -49,6 +49,10 @@ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +struct omap_spi_drvdata { + unsigned register_offset; +}; + static void spi_reset(struct spi_master *master) { struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master); @@ -343,6 +347,12 @@ static int omap3_spi_probe(struct device_d *dev) { struct spi_master *master; struct omap3_spi_master *omap3_master; + struct omap_spi_drvdata *devtype; + int ret; + + ret = dev_get_drvdata(dev, (unsigned long *)&devtype); + if (ret) + return ret; omap3_master = xzalloc(sizeof(*omap3_master)); @@ -374,7 +384,10 @@ static int omap3_spi_probe(struct device_d *dev) master->setup = omap3_spi_setup; master->transfer = omap3_spi_transfer; - omap3_master->regs = dev_request_mem_region(dev, 0); + omap3_master->base = dev_request_mem_region(dev, 0); + omap3_master->regs = omap3_master->base; + + omap3_master->regs += devtype->register_offset; spi_reset(master); @@ -383,8 +396,42 @@ static int omap3_spi_probe(struct device_d *dev) return 0; } +static struct omap_spi_drvdata omap3_data = { + .register_offset = 0x0, +}; + +static struct omap_spi_drvdata omap4_data = { + .register_offset = 0x100, +}; + +static __maybe_unused struct of_device_id omap_spi_dt_ids[] = { + { + .compatible = "ti,omap2-mcspi", + .data = (unsigned long)&omap3_data, + }, { + .compatible = "ti,omap4-mcspi", + .data = (unsigned long)&omap4_data, + }, { + /* sentinel */ + } +}; + +static struct platform_device_id omap_spi_ids[] = { + { + .name = "omap3-spi", + .driver_data = (unsigned long)&omap3_data, + }, { + .name = "omap4-spi", + .driver_data = (unsigned long)&omap4_data, + }, { + /* sentinel */ + }, +}; + static struct driver_d omap3_spi_driver = { - .name = "omap3_spi", + .name = "omap-spi", .probe = omap3_spi_probe, + .of_compatible = DRV_OF_COMPAT(omap_spi_dt_ids), + .id_table = omap_spi_ids, }; device_platform_driver(omap3_spi_driver); diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h index 55fd2fcc4..ce4a29bed 100644 --- a/drivers/spi/omap3_spi.h +++ b/drivers/spi/omap3_spi.h @@ -88,7 +88,11 @@ struct omap3_spi_master { struct spi_master master; - void __iomem *regs; + void __iomem *base; /* base of address space */ + void __iomem *regs; /* actual start of registers, omap4/am33xx have an + * offset of 0x100 between start of register space + * and registers + */ }; #endif /* _OMAP3_SPI_H_ */ diff --git a/include/driver.h b/include/driver.h index 7f0532e1a..bbe789b51 100644 --- a/include/driver.h +++ b/include/driver.h @@ -229,6 +229,15 @@ void *dev_get_mem_region(struct device_d *dev, int num); */ void __iomem *dev_request_mem_region(struct device_d *dev, int num); +struct device_d *device_alloc(const char *devname, int id); + +int device_add_resources(struct device_d *dev, const struct resource *res, int num); + +int device_add_resource(struct device_d *dev, const char *resname, + resource_size_t start, resource_size_t size, unsigned int flags); + +int device_add_data(struct device_d *dev, void *data, size_t size); + /* * register a generic device * with only one resource diff --git a/include/pinctrl.h b/include/pinctrl.h index 7323f8b2f..0f03b10be 100644 --- a/include/pinctrl.h +++ b/include/pinctrl.h @@ -20,6 +20,8 @@ void pinctrl_unregister(struct pinctrl_device *pdev); #ifdef CONFIG_PINCTRL int pinctrl_select_state(struct device_d *dev, const char *state); int pinctrl_select_state_default(struct device_d *dev); +int of_pinctrl_select_state(struct device_node *np, const char *state); +int of_pinctrl_select_state_default(struct device_node *np); #else static inline int pinctrl_select_state(struct device_d *dev, const char *state) { @@ -30,6 +32,16 @@ static inline int pinctrl_select_state_default(struct device_d *dev) { return -ENODEV; } + +static inline int of_pinctrl_select_state(struct device_node *np, const char *state) +{ + return -ENODEV; +} + +static inline int of_pinctrl_select_state_default(struct device_node *np) +{ + return -ENODEV; +} #endif #endif /* PINCTRL_H */ diff --git a/include/string.h b/include/string.h index b906e1504..a833da131 100644 --- a/include/string.h +++ b/include/string.h @@ -3,4 +3,6 @@ #include +void *memdup(const void *, size_t); + #endif /* __STRING_H */ diff --git a/include/xfuncs.h b/include/xfuncs.h index 261aaa5c1..8efc99dbc 100644 --- a/include/xfuncs.h +++ b/include/xfuncs.h @@ -8,5 +8,6 @@ void *xrealloc(void *ptr, size_t size); void *xzalloc(size_t size); char *xstrdup(const char *s); void* xmemalign(size_t alignment, size_t bytes); +void* xmemdup(const void *orig, size_t size); #endif /* __XFUNCS_H */ diff --git a/lib/string.c b/lib/string.c index eeec137c9..ceced7f48 100644 --- a/lib/string.c +++ b/lib/string.c @@ -725,3 +725,17 @@ void *memchr_inv(const void *start, int c, size_t bytes) return check_bytes8(start, value, bytes % 8); } EXPORT_SYMBOL(memchr_inv); + +void *memdup(const void *orig, size_t size) +{ + void *buf; + + buf = malloc(size); + if (!buf) + return NULL; + + memcpy(buf, orig, size); + + return buf; +} +EXPORT_SYMBOL(memdup); diff --git a/lib/xfuncs.c b/lib/xfuncs.c index db8572019..86d001378 100644 --- a/lib/xfuncs.c +++ b/lib/xfuncs.c @@ -75,3 +75,13 @@ void* xmemalign(size_t alignment, size_t bytes) return p; } EXPORT_SYMBOL(xmemalign); + +void *xmemdup(const void *orig, size_t size) +{ + void *buf = xmalloc(size); + + memcpy(buf, orig, size); + + return buf; +} +EXPORT_SYMBOL(xmemdup);