Merge branch 'for-next/omap-drivers'
This commit is contained in:
commit
ed039cd72b
|
@ -31,5 +31,4 @@ obj-$(CONFIG_SHELL_NONE) += xload.o
|
||||||
obj-$(CONFIG_MFD_TWL6030) += omap4_twl6030_mmc.o
|
obj-$(CONFIG_MFD_TWL6030) += omap4_twl6030_mmc.o
|
||||||
obj-$(CONFIG_OMAP4_USBBOOT) += omap4_rom_usb.o
|
obj-$(CONFIG_OMAP4_USBBOOT) += omap4_rom_usb.o
|
||||||
obj-$(CONFIG_CMD_BOOT_ORDER) += boot_order.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
|
obj-$(CONFIG_BAREBOX_UPDATE_AM33XX_SPI_NOR_MLO) += am33xx_bbu_spi_mlo.o
|
||||||
|
|
|
@ -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);
|
void __iomem *reg = GPMC_REG(CONFIG1_0) + (cs * GPMC_CONFIG_CS_SIZE);
|
||||||
unsigned char x = 0;
|
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 */
|
/* Disable the CS before reconfiguring */
|
||||||
writel(0x0, GPMC_REG(CONFIG7_0) + (cs * GPMC_CONFIG_CS_SIZE));
|
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 */
|
/* Write the CFG1-6 regs */
|
||||||
while (x < 6) {
|
while (x < 6) {
|
||||||
debug("gpmccfg%d Reg:0x%p <-0x%08x\n",
|
debug("gpmccfg%d Reg:0x%p <-0x%08x, old 0x%08x\n",
|
||||||
x, reg, config->cfg[x]);
|
x, reg, config->cfg[x], readl(reg));
|
||||||
writel(config->cfg[x], reg);
|
writel(config->cfg[x], reg);
|
||||||
reg += GPMC_CONFIG_REG_OFF;
|
reg += GPMC_CONFIG_REG_OFF;
|
||||||
x++;
|
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->size & 0xF) << 8) | /* Size */
|
||||||
((config->base >> 24) & 0x3F), /* Address */
|
((config->base >> 24) & 0x3F);
|
||||||
reg);
|
|
||||||
|
debug("gpmccfg%d Reg:0x%p <-0x%08x, old 0x%08x\n",
|
||||||
|
x, reg, config7, readl(reg));
|
||||||
|
|
||||||
|
writel(config7, reg);
|
||||||
|
|
||||||
mdelay(1); /* Settling time */
|
mdelay(1); /* Settling time */
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(gpmc_cs_config);
|
EXPORT_SYMBOL(gpmc_cs_config);
|
||||||
|
|
|
@ -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)
|
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);
|
IORESOURCE_MEM, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,9 @@ struct gpmc_nand_platform_data {
|
||||||
struct nand_ecclayout *oob;
|
struct nand_ecclayout *oob;
|
||||||
/** gpmc config for nand */
|
/** gpmc config for nand */
|
||||||
struct gpmc_config *nand_cfg;
|
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);
|
int omap_add_gpmc_nand_device(struct gpmc_nand_platform_data *pdata);
|
||||||
|
|
|
@ -21,6 +21,6 @@ static struct NS16550_plat serial_plat = {
|
||||||
|
|
||||||
struct device_d *omap_add_uart(int id, unsigned long base)
|
struct device_d *omap_add_uart(int id, unsigned long base)
|
||||||
{
|
{
|
||||||
return add_ns16550_device(id, base, 1024,
|
return add_generic_device("omap-uart", id, NULL, base, 1024,
|
||||||
IORESOURCE_MEM_8BIT, &serial_plat);
|
IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &serial_plat);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,33 +20,67 @@
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <driver.h>
|
#include <driver.h>
|
||||||
#include <xfuncs.h>
|
#include <xfuncs.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
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;
|
struct device_d *dev;
|
||||||
|
|
||||||
dev = xzalloc(sizeof(*dev));
|
dev = xzalloc(sizeof(*dev));
|
||||||
strcpy(dev->name, devname);
|
strcpy(dev->name, devname);
|
||||||
dev->id = id;
|
dev->id = id;
|
||||||
dev->platform_data = pdata;
|
|
||||||
|
|
||||||
return dev;
|
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,
|
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,
|
resource_size_t start, resource_size_t size, unsigned int flags,
|
||||||
void *pdata)
|
void *pdata)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct device_d *dev;
|
||||||
|
|
||||||
res = xzalloc(sizeof(struct resource));
|
dev = device_alloc(devname, id);
|
||||||
if (resname)
|
dev->platform_data = pdata;
|
||||||
res[0].name = xstrdup(resname);
|
device_add_resource(dev, resname, start, size, flags);
|
||||||
res[0].start = start;
|
|
||||||
res[0].end = start + size - 1;
|
|
||||||
res[0].flags = flags;
|
|
||||||
|
|
||||||
return add_generic_device_res(devname, id, res, 1, pdata);
|
platform_device_register(dev);
|
||||||
|
|
||||||
|
return dev;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(add_generic_device);
|
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;
|
struct device_d *dev;
|
||||||
|
|
||||||
dev = alloc_device(devname, id, pdata);
|
dev = device_alloc(devname, id);
|
||||||
dev->resource = res;
|
dev->platform_data = pdata;
|
||||||
dev->num_resources = nb;
|
device_add_resources(dev, res, nb);
|
||||||
|
|
||||||
platform_device_register(dev);
|
platform_device_register(dev);
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,10 @@ config IMX_WEIM
|
||||||
depends on ARCH_IMX
|
depends on ARCH_IMX
|
||||||
bool "i.MX WEIM driver"
|
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
|
endmenu
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
|
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
|
||||||
|
obj-$(CONFIG_BUS_OMAP_GPMC) += omap-gpmc.o
|
||||||
|
|
|
@ -0,0 +1,523 @@
|
||||||
|
/*
|
||||||
|
* OMAP GPMC driver. Based upon the corresponding Linux Code
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Sascha Hauer, Pengutronix, <s.hauer@pengutronix.de>
|
||||||
|
*
|
||||||
|
* 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 <common.h>
|
||||||
|
#include <driver.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <sizes.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <of.h>
|
||||||
|
#include <of_address.h>
|
||||||
|
#include <of_mtd.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <mach/gpmc_nand.h>
|
||||||
|
#include <mach/gpmc.h>
|
||||||
|
|
||||||
|
#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);
|
|
@ -30,6 +30,9 @@ config GPIO_GENERIC_PLATFORM
|
||||||
config GPIO_IMX
|
config GPIO_IMX
|
||||||
def_bool ARCH_IMX
|
def_bool ARCH_IMX
|
||||||
|
|
||||||
|
config GPIO_OMAP
|
||||||
|
def_bool ARCH_OMAP
|
||||||
|
|
||||||
config GPIO_ORION
|
config GPIO_ORION
|
||||||
bool "GPIO support for Marvell Orion/MVEBU SoCs"
|
bool "GPIO support for Marvell Orion/MVEBU SoCs"
|
||||||
depends on ARCH_MVEBU
|
depends on ARCH_MVEBU
|
||||||
|
|
|
@ -5,6 +5,7 @@ obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
|
||||||
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
|
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
|
||||||
obj-$(CONFIG_GPIO_IMX) += gpio-imx.o
|
obj-$(CONFIG_GPIO_IMX) += gpio-imx.o
|
||||||
obj-$(CONFIG_GPIO_ORION) += gpio-orion.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_PL061) += gpio-pl061.o
|
||||||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||||
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
|
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
|
||||||
|
|
|
@ -48,6 +48,18 @@ struct omap_gpio_chip {
|
||||||
struct gpio_chip 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)
|
static inline int omap_get_gpio_index(int gpio)
|
||||||
{
|
{
|
||||||
return gpio & 0x1f;
|
return gpio & 0x1f;
|
||||||
|
@ -129,11 +141,24 @@ static struct gpio_ops omap_gpio_ops = {
|
||||||
static int omap_gpio_probe(struct device_d *dev)
|
static int omap_gpio_probe(struct device_d *dev)
|
||||||
{
|
{
|
||||||
struct omap_gpio_chip *omapgpio;
|
struct omap_gpio_chip *omapgpio;
|
||||||
|
struct omap_gpio_drvdata *drvdata = NULL;
|
||||||
|
|
||||||
|
dev_get_drvdata(dev, (unsigned long *)&drvdata);
|
||||||
|
|
||||||
omapgpio = xzalloc(sizeof(*omapgpio));
|
omapgpio = xzalloc(sizeof(*omapgpio));
|
||||||
omapgpio->base = dev_request_mem_region(dev, 0);
|
omapgpio->base = dev_request_mem_region(dev, 0);
|
||||||
|
if (drvdata)
|
||||||
|
omapgpio->base += drvdata->regofs;
|
||||||
|
|
||||||
omapgpio->chip.ops = &omap_gpio_ops;
|
omapgpio->chip.ops = &omap_gpio_ops;
|
||||||
|
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.base = dev->id * 32;
|
||||||
|
}
|
||||||
omapgpio->chip.ngpio = 32;
|
omapgpio->chip.ngpio = 32;
|
||||||
omapgpio->chip.dev = dev;
|
omapgpio->chip.dev = dev;
|
||||||
gpiochip_add(&omapgpio->chip);
|
gpiochip_add(&omapgpio->chip);
|
||||||
|
@ -144,9 +169,21 @@ static int omap_gpio_probe(struct device_d *dev)
|
||||||
return 0;
|
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 = {
|
static struct driver_d omap_gpio_driver = {
|
||||||
.name = "omap-gpio",
|
.name = "omap-gpio",
|
||||||
.probe = omap_gpio_probe,
|
.probe = omap_gpio_probe,
|
||||||
|
.of_compatible = DRV_OF_COMPAT(omap_gpio_dt_ids),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int omap_gpio_add(void)
|
static int omap_gpio_add(void)
|
|
@ -151,6 +151,7 @@ struct omap_i2c_struct {
|
||||||
u8 reg_shift;
|
u8 reg_shift;
|
||||||
struct omap_i2c_driver_data *data;
|
struct omap_i2c_driver_data *data;
|
||||||
struct resource *ioarea;
|
struct resource *ioarea;
|
||||||
|
u32 fclk_rate;
|
||||||
u32 speed; /* Speed of bus in Khz */
|
u32 speed; /* Speed of bus in Khz */
|
||||||
u16 scheme;
|
u16 scheme;
|
||||||
u16 cmd_err;
|
u16 cmd_err;
|
||||||
|
@ -271,6 +272,11 @@ static struct omap_i2c_driver_data am33xx_data = {
|
||||||
.fclk_rate = 48000,
|
.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,
|
static inline void omap_i2c_write_reg(struct omap_i2c_struct *i2c_omap,
|
||||||
int reg, u16 val)
|
int reg, u16 val)
|
||||||
{
|
{
|
||||||
|
@ -415,7 +421,7 @@ static int omap_i2c_init(struct omap_i2c_struct *i2c_omap)
|
||||||
internal_clk = 4000;
|
internal_clk = 4000;
|
||||||
|
|
||||||
/* Compute prescaler divisor */
|
/* Compute prescaler divisor */
|
||||||
psc = i2c_data->fclk_rate / internal_clk;
|
psc = i2c_omap->fclk_rate / internal_clk;
|
||||||
psc = psc - 1;
|
psc = psc - 1;
|
||||||
|
|
||||||
/* If configured for High Speed */
|
/* 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->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 */
|
/* reset ASAP, clearing any IRQs */
|
||||||
omap_i2c_init(i2c_omap);
|
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.master_xfer = omap_i2c_xfer,
|
||||||
i2c_omap->adapter.nr = pdev->id;
|
i2c_omap->adapter.nr = pdev->id;
|
||||||
i2c_omap->adapter.dev.parent = pdev;
|
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() */
|
/* i2c device drivers may be active on return from add_adapter() */
|
||||||
r = i2c_add_numbered_adapter(&i2c_omap->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 = {
|
static struct driver_d omap_i2c_driver = {
|
||||||
.probe = i2c_omap_probe,
|
.probe = i2c_omap_probe,
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.id_table = omap_i2c_ids,
|
.id_table = omap_i2c_ids,
|
||||||
|
.of_compatible = DRV_OF_COMPAT(omap_spi_dt_ids),
|
||||||
};
|
};
|
||||||
device_platform_driver(omap_i2c_driver);
|
device_platform_driver(omap_i2c_driver);
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
static struct driver_d omap_mmc_driver = {
|
||||||
.name = "omap-hsmmc",
|
.name = "omap-hsmmc",
|
||||||
.probe = omap_mmc_probe,
|
.probe = omap_mmc_probe,
|
||||||
.id_table = omap_mmc_ids,
|
.id_table = omap_mmc_ids,
|
||||||
|
.of_compatible = DRV_OF_COMPAT(omap_mmc_dt_ids),
|
||||||
};
|
};
|
||||||
device_platform_driver(omap_mmc_driver);
|
device_platform_driver(omap_mmc_driver);
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
|
|
||||||
int omap_gpmc_decode_bch(int select_4_8, unsigned char *ecc, unsigned int *err_loc);
|
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",
|
"software",
|
||||||
"hamming_hw_romcode",
|
"hamming_hw_romcode",
|
||||||
"bch4_hw",
|
"bch4_hw",
|
||||||
|
@ -861,29 +861,11 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
|
||||||
return 0;
|
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;
|
struct gpmc_nand_info *oinfo = priv;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!val)
|
return omap_gpmc_eccmode(oinfo, oinfo->ecc_mode);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpmc_set_buswidth(struct nand_chip *chip, int buswidth)
|
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;
|
nand->options |= NAND_SKIP_BBTSCAN;
|
||||||
|
|
||||||
dev_add_param(pdev, "eccmode", omap_gpmc_eccmode_set, NULL, 0);
|
oinfo->ecc_mode = pdata->ecc_mode;
|
||||||
dev_set_param(pdev, "eccmode", ecc_mode_strings[pdata->ecc_mode]);
|
|
||||||
|
|
||||||
if (! IS_ENABLED(CONFIG_PARAMETER))
|
dev_add_param_enum(pdev, "eccmode",
|
||||||
omap_gpmc_eccmode(oinfo, pdata->ecc_mode);
|
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! */
|
/* We are all set to register with the system now! */
|
||||||
err = add_mtd_nand_device(minfo, "nand");
|
err = add_mtd_nand_device(minfo, "nand");
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <of.h>
|
||||||
|
#include <pinctrl.h>
|
||||||
|
#include <of_net.h>
|
||||||
|
#include <of_address.h>
|
||||||
#include <xfuncs.h>
|
#include <xfuncs.h>
|
||||||
#include <asm/mmu.h>
|
#include <asm/mmu.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
@ -175,7 +179,10 @@ struct cpsw_slave {
|
||||||
struct cpsw_sliver_regs *sliver;
|
struct cpsw_sliver_regs *sliver;
|
||||||
int slave_num;
|
int slave_num;
|
||||||
u32 mac_control;
|
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 {
|
struct cpdma_desc {
|
||||||
|
@ -196,7 +203,6 @@ struct cpdma_chan {
|
||||||
|
|
||||||
struct cpsw_priv {
|
struct cpsw_priv {
|
||||||
struct device_d *dev;
|
struct device_d *dev;
|
||||||
struct eth_device edev;
|
|
||||||
struct mii_bus miibus;
|
struct mii_bus miibus;
|
||||||
|
|
||||||
u32 version;
|
u32 version;
|
||||||
|
@ -223,12 +229,6 @@ struct cpsw_priv {
|
||||||
struct cpdma_chan rx_chan, tx_chan;
|
struct cpdma_chan rx_chan, tx_chan;
|
||||||
|
|
||||||
struct cpsw_slave *slaves;
|
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)
|
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))
|
((mac)[2] << 16) | ((mac)[3] << 24))
|
||||||
#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8))
|
#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)
|
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__);
|
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)
|
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__);
|
dev_dbg(priv->dev, "* %s\n", __func__);
|
||||||
|
|
||||||
memcpy(&priv->mac_addr, mac, sizeof(priv->mac_addr));
|
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;
|
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,
|
static void cpsw_slave_update_link(struct cpsw_slave *slave,
|
||||||
struct cpsw_priv *priv, int *link)
|
struct cpsw_priv *priv, int *link)
|
||||||
{
|
{
|
||||||
struct phy_device *phydev = priv->edev.phydev;
|
struct phy_device *phydev = slave->edev.phydev;
|
||||||
u32 mac_control = 0;
|
u32 mac_control = 0;
|
||||||
|
|
||||||
dev_dbg(priv->dev, "* %s\n", __func__);
|
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;
|
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;
|
int link = 0;
|
||||||
|
|
||||||
dev_dbg(priv->dev, "* %s\n", __func__);
|
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;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpsw_adjust_link(struct eth_device *edev) {
|
static void cpsw_adjust_link(struct eth_device *edev)
|
||||||
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__);
|
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)
|
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)
|
static int cpsw_open(struct eth_device *edev)
|
||||||
{
|
{
|
||||||
struct cpsw_priv *priv = edev->priv;
|
struct cpsw_slave *slave = edev->priv;
|
||||||
struct cpsw_slave_data *slave_data = priv->data.slave_data;
|
struct cpsw_priv *priv = slave->cpsw;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
dev_dbg(priv->dev, "* %s\n", __func__);
|
dev_dbg(priv->dev, "* %s\n", __func__);
|
||||||
|
|
||||||
ret = phy_device_connect(edev, &priv->miibus, slave_data[0].phy_id,
|
ret = phy_device_connect(edev, &priv->miibus, slave->phy_id,
|
||||||
cpsw_adjust_link, 0, slave_data[0].phy_if);
|
cpsw_adjust_link, 0, slave->phy_if);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -800,9 +796,8 @@ static int cpsw_open(struct eth_device *edev)
|
||||||
ALE_SECURE);
|
ALE_SECURE);
|
||||||
cpsw_ale_add_mcast(priv, ethbdaddr, 1 << priv->host_port);
|
cpsw_ale_add_mcast(priv, ethbdaddr, 1 << priv->host_port);
|
||||||
|
|
||||||
for_each_slave(priv, cpsw_slave_init, priv);
|
cpsw_slave_init(&priv->slaves[0], priv);
|
||||||
|
cpsw_update_link(&priv->slaves[0], priv);
|
||||||
cpsw_update_link(priv);
|
|
||||||
|
|
||||||
/* init descriptor pool */
|
/* init descriptor pool */
|
||||||
for (i = 0; i < NUM_DESCS; i++) {
|
for (i = 0; i < NUM_DESCS; i++) {
|
||||||
|
@ -850,9 +845,10 @@ static int cpsw_open(struct eth_device *edev)
|
||||||
return 0;
|
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_TXCONTROL);
|
||||||
writel(0, priv->dma_regs + CPDMA_RXCONTROL);
|
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);
|
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;
|
void *buffer;
|
||||||
int ret, len;
|
int ret, len;
|
||||||
|
|
||||||
|
@ -884,9 +881,10 @@ static int cpsw_send(struct eth_device *dev, void *packet, int length)
|
||||||
return ret;
|
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;
|
void *buffer;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
@ -899,18 +897,39 @@ static int cpsw_recv(struct eth_device *dev)
|
||||||
return 0;
|
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)
|
struct cpsw_priv *priv)
|
||||||
{
|
{
|
||||||
void *regs = priv->regs;
|
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__);
|
dev_dbg(priv->dev, "* %s\n", __func__);
|
||||||
|
|
||||||
slave->slave_num = slave_num;
|
slave->slave_num = slave_num;
|
||||||
slave->data = data;
|
|
||||||
slave->regs = regs + priv->slave_ofs + priv->slave_size * slave_num;
|
slave->regs = regs + priv->slave_ofs + priv->slave_size * slave_num;
|
||||||
slave->sliver = regs + priv->sliver_ofs + SLIVER_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 {
|
struct cpsw_data {
|
||||||
|
@ -948,15 +967,139 @@ static struct cpsw_data cpsw2_data = {
|
||||||
.cppi_ram_ofs = 0x2000,
|
.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)
|
int cpsw_probe(struct device_d *dev)
|
||||||
{
|
{
|
||||||
struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data;
|
struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data;
|
||||||
struct cpsw_priv *priv;
|
struct cpsw_priv *priv;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
struct eth_device *edev;
|
|
||||||
uint64_t start;
|
uint64_t start;
|
||||||
uint32_t phy_mask;
|
uint32_t phy_mask;
|
||||||
struct cpsw_data *cpsw_data;
|
struct cpsw_data *cpsw_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
dev_dbg(dev, "* %s\n", __func__);
|
dev_dbg(dev, "* %s\n", __func__);
|
||||||
|
|
||||||
|
@ -964,13 +1107,20 @@ int cpsw_probe(struct device_d *dev)
|
||||||
|
|
||||||
priv = xzalloc(sizeof(*priv));
|
priv = xzalloc(sizeof(*priv));
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
priv->data = *data;
|
|
||||||
priv->channels = 8;
|
|
||||||
priv->num_slaves = data->num_slaves;
|
|
||||||
priv->ale_entries = 1024;
|
|
||||||
edev = &priv->edev;
|
|
||||||
|
|
||||||
|
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);
|
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->host_port = 0;
|
||||||
priv->regs = regs;
|
priv->regs = regs;
|
||||||
|
@ -985,7 +1135,8 @@ int cpsw_probe(struct device_d *dev)
|
||||||
cpsw_data = &cpsw2_data;
|
cpsw_data = &cpsw2_data;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->descs = regs + cpsw_data->cppi_ram_ofs;
|
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->slave_size = cpsw_data->slave_size;
|
||||||
priv->sliver_ofs = cpsw_data->sliver_ofs;
|
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.read = cpsw_mdio_read;
|
||||||
priv->miibus.write = cpsw_mdio_write;
|
priv->miibus.write = cpsw_mdio_write;
|
||||||
priv->miibus.priv = priv;
|
priv->miibus.priv = priv;
|
||||||
|
@ -1052,13 +1191,29 @@ int cpsw_probe(struct device_d *dev)
|
||||||
|
|
||||||
mdiobus_register(&priv->miibus);
|
mdiobus_register(&priv->miibus);
|
||||||
|
|
||||||
eth_register(edev);
|
ret = cpsw_slave_setup(&priv->slaves[0], 0, priv);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static struct driver_d cpsw_driver = {
|
||||||
.name = "cpsw",
|
.name = "cpsw",
|
||||||
.probe = cpsw_probe,
|
.probe = cpsw_probe,
|
||||||
|
.of_compatible = DRV_OF_COMPAT(cpsw_dt_ids),
|
||||||
};
|
};
|
||||||
device_platform_driver(cpsw_driver);
|
device_platform_driver(cpsw_driver);
|
||||||
|
|
|
@ -23,6 +23,9 @@ config PINCTRL_IMX_IOMUX_V3
|
||||||
help
|
help
|
||||||
This iomux controller is found on i.MX25,35,51,53,6.
|
This iomux controller is found on i.MX25,35,51,53,6.
|
||||||
|
|
||||||
|
config PINCTRL_SINGLE
|
||||||
|
bool "pinctrl single"
|
||||||
|
|
||||||
config PINCTRL_TEGRA20
|
config PINCTRL_TEGRA20
|
||||||
select PINCTRL
|
select PINCTRL
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -2,4 +2,5 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o
|
||||||
obj-$(CONFIG_PINCTRL_IMX_IOMUX_V1) += imx-iomux-v1.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_V2) += imx-iomux-v2.o
|
||||||
obj-$(CONFIG_PINCTRL_IMX_IOMUX_V3) += imx-iomux-v3.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
|
obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
|
||||||
|
|
|
@ -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 <s.hauer@pengutronix.de>
|
||||||
|
*
|
||||||
|
* 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 <common.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <pinctrl.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
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);
|
|
@ -51,7 +51,7 @@ static int pinctrl_config_one(struct device_node *np)
|
||||||
return pdev->ops->set_state(pdev, 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;
|
int state, ret;
|
||||||
char *propname;
|
char *propname;
|
||||||
|
@ -59,13 +59,9 @@ int pinctrl_select_state(struct device_d *dev, const char *name)
|
||||||
const __be32 *list;
|
const __be32 *list;
|
||||||
int size, config;
|
int size, config;
|
||||||
phandle phandle;
|
phandle phandle;
|
||||||
struct device_node *np_config, *np;
|
struct device_node *np_config;
|
||||||
const char *statename;
|
const char *statename;
|
||||||
|
|
||||||
np = dev->device_node;
|
|
||||||
if (!np)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!of_find_property(np, "pinctrl-0", NULL))
|
if (!of_find_property(np, "pinctrl-0", NULL))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -127,6 +123,22 @@ err:
|
||||||
return ret;
|
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)
|
int pinctrl_select_state_default(struct device_d *dev)
|
||||||
{
|
{
|
||||||
return pinctrl_select_state(dev, "default");
|
return pinctrl_select_state(dev, "default");
|
||||||
|
|
|
@ -55,6 +55,10 @@ static inline struct ns16550_priv *to_ns16550_priv(struct console_device *cdev)
|
||||||
return container_of(cdev, struct ns16550_priv, cdev);
|
return container_of(cdev, struct ns16550_priv, cdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ns16550_drvdata {
|
||||||
|
void (*init_port)(struct console_device *cdev);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief read register
|
* @brief read register
|
||||||
*
|
*
|
||||||
|
@ -178,14 +182,16 @@ static void ns16550_serial_init_port(struct console_device *cdev)
|
||||||
/* initializing the device for the first time */
|
/* initializing the device for the first time */
|
||||||
ns16550_write(cdev, 0x00, lcr); /* select ier reg */
|
ns16550_write(cdev, 0x00, lcr); /* select ier reg */
|
||||||
ns16550_write(cdev, 0x00, ier);
|
ns16550_write(cdev, 0x00, ier);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
|
#define omap_mdr1 8
|
||||||
ns16550_write(cdev, 0x07, mdr1); /* Disable */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
|
static void ns16550_omap_init_port(struct console_device *cdev)
|
||||||
ns16550_write(cdev, 0x00, mdr1);
|
{
|
||||||
#endif
|
ns16550_serial_init_port(cdev);
|
||||||
|
|
||||||
|
ns16550_write(cdev, 0x07, omap_mdr1); /* Disable */
|
||||||
|
ns16550_write(cdev, 0x00, omap_mdr1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********** Exposed Functions **********************************/
|
/*********** 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);
|
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
|
* @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 ns16550_priv *priv;
|
||||||
struct console_device *cdev;
|
struct console_device *cdev;
|
||||||
struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data;
|
struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data;
|
||||||
|
struct ns16550_drvdata *devtype;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = dev_get_drvdata(dev, (unsigned long *)&devtype);
|
||||||
|
if (ret)
|
||||||
|
devtype = &ns16550_drvdata;
|
||||||
|
|
||||||
dev->priv = dev_request_mem_region(dev, 0);
|
dev->priv = dev_request_mem_region(dev, 0);
|
||||||
|
|
||||||
priv = xzalloc(sizeof(*priv));
|
priv = xzalloc(sizeof(*priv));
|
||||||
|
@ -294,7 +313,7 @@ static int ns16550_probe(struct device_d *dev)
|
||||||
cdev->getc = ns16550_getc;
|
cdev->getc = ns16550_getc;
|
||||||
cdev->setbrg = ns16550_setbaudrate;
|
cdev->setbrg = ns16550_setbaudrate;
|
||||||
|
|
||||||
ns16550_serial_init_port(cdev);
|
devtype->init_port(cdev);
|
||||||
|
|
||||||
return console_register(cdev);
|
return console_register(cdev);
|
||||||
|
|
||||||
|
@ -307,8 +326,32 @@ err:
|
||||||
static struct of_device_id ns16550_serial_dt_ids[] = {
|
static struct of_device_id ns16550_serial_dt_ids[] = {
|
||||||
{
|
{
|
||||||
.compatible = "ns16550a",
|
.compatible = "ns16550a",
|
||||||
},{
|
.data = (unsigned long)&ns16550_drvdata,
|
||||||
|
}, {
|
||||||
.compatible = "snps,dw-apb-uart",
|
.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 */
|
/* sentinel */
|
||||||
},
|
},
|
||||||
|
@ -321,5 +364,8 @@ static struct driver_d ns16550_serial_driver = {
|
||||||
.name = "ns16550_serial",
|
.name = "ns16550_serial",
|
||||||
.probe = ns16550_probe,
|
.probe = ns16550_probe,
|
||||||
.of_compatible = DRV_OF_COMPAT(ns16550_serial_dt_ids),
|
.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);
|
console_platform_driver(ns16550_serial_driver);
|
||||||
|
|
|
@ -40,10 +40,6 @@
|
||||||
#define lsr 5
|
#define lsr 5
|
||||||
#define msr 6
|
#define msr 6
|
||||||
#define scr 7
|
#define scr 7
|
||||||
#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
|
|
||||||
#define mdr1 8
|
|
||||||
#define osc_12m_sel 9
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define thr rbr
|
#define thr rbr
|
||||||
#define iir fcr
|
#define iir fcr
|
||||||
|
|
|
@ -49,6 +49,10 @@
|
||||||
#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
|
#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
|
||||||
#define SPI_XFER_END 0x02 /* Deassert CS after 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)
|
static void spi_reset(struct spi_master *master)
|
||||||
{
|
{
|
||||||
struct omap3_spi_master *omap3_master = container_of(master, struct omap3_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 spi_master *master;
|
||||||
struct omap3_spi_master *omap3_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));
|
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->setup = omap3_spi_setup;
|
||||||
master->transfer = omap3_spi_transfer;
|
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);
|
spi_reset(master);
|
||||||
|
|
||||||
|
@ -383,8 +396,42 @@ static int omap3_spi_probe(struct device_d *dev)
|
||||||
return 0;
|
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 = {
|
static struct driver_d omap3_spi_driver = {
|
||||||
.name = "omap3_spi",
|
.name = "omap-spi",
|
||||||
.probe = omap3_spi_probe,
|
.probe = omap3_spi_probe,
|
||||||
|
.of_compatible = DRV_OF_COMPAT(omap_spi_dt_ids),
|
||||||
|
.id_table = omap_spi_ids,
|
||||||
};
|
};
|
||||||
device_platform_driver(omap3_spi_driver);
|
device_platform_driver(omap3_spi_driver);
|
||||||
|
|
|
@ -88,7 +88,11 @@
|
||||||
|
|
||||||
struct omap3_spi_master {
|
struct omap3_spi_master {
|
||||||
struct spi_master 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_ */
|
#endif /* _OMAP3_SPI_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);
|
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
|
* register a generic device
|
||||||
* with only one resource
|
* with only one resource
|
||||||
|
|
|
@ -20,6 +20,8 @@ void pinctrl_unregister(struct pinctrl_device *pdev);
|
||||||
#ifdef CONFIG_PINCTRL
|
#ifdef CONFIG_PINCTRL
|
||||||
int pinctrl_select_state(struct device_d *dev, const char *state);
|
int pinctrl_select_state(struct device_d *dev, const char *state);
|
||||||
int pinctrl_select_state_default(struct device_d *dev);
|
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
|
#else
|
||||||
static inline int pinctrl_select_state(struct device_d *dev, const char *state)
|
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;
|
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
|
||||||
|
|
||||||
#endif /* PINCTRL_H */
|
#endif /* PINCTRL_H */
|
||||||
|
|
|
@ -3,4 +3,6 @@
|
||||||
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
void *memdup(const void *, size_t);
|
||||||
|
|
||||||
#endif /* __STRING_H */
|
#endif /* __STRING_H */
|
||||||
|
|
|
@ -8,5 +8,6 @@ void *xrealloc(void *ptr, size_t size);
|
||||||
void *xzalloc(size_t size);
|
void *xzalloc(size_t size);
|
||||||
char *xstrdup(const char *s);
|
char *xstrdup(const char *s);
|
||||||
void* xmemalign(size_t alignment, size_t bytes);
|
void* xmemalign(size_t alignment, size_t bytes);
|
||||||
|
void* xmemdup(const void *orig, size_t size);
|
||||||
|
|
||||||
#endif /* __XFUNCS_H */
|
#endif /* __XFUNCS_H */
|
||||||
|
|
14
lib/string.c
14
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);
|
return check_bytes8(start, value, bytes % 8);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(memchr_inv);
|
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);
|
||||||
|
|
10
lib/xfuncs.c
10
lib/xfuncs.c
|
@ -75,3 +75,13 @@ void* xmemalign(size_t alignment, size_t bytes)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(xmemalign);
|
EXPORT_SYMBOL(xmemalign);
|
||||||
|
|
||||||
|
void *xmemdup(const void *orig, size_t size)
|
||||||
|
{
|
||||||
|
void *buf = xmalloc(size);
|
||||||
|
|
||||||
|
memcpy(buf, orig, size);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(xmemdup);
|
||||||
|
|
Loading…
Reference in New Issue