diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/ahci.c | 4 | ||||
-rw-r--r-- | drivers/mmc/omap_hsmmc.c | 4 | ||||
-rw-r--r-- | drivers/net/cpsw.c | 29 | ||||
-rw-r--r-- | drivers/rtc/pl031.c | 126 | ||||
-rw-r--r-- | drivers/serial/serial_efi.c | 2 | ||||
-rw-r--r-- | drivers/serial/serial_omap.c | 1 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/pl022_spi.c | 338 | ||||
-rw-r--r-- | drivers/video/vidconsole-uclass.c | 8 |
10 files changed, 473 insertions, 48 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c35912bd33..5fafb63aeb 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -230,8 +230,10 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv) debug("cap 0x%x port_map 0x%x n_ports %d\n", uc_priv->cap, uc_priv->port_map, uc_priv->n_ports); +#if !defined(CONFIG_DM_SCSI) if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; +#endif for (i = 0; i < uc_priv->n_ports; i++) { if (!(port_map & (1 << i))) @@ -980,7 +982,7 @@ static int ahci_start_ports(struct ahci_uc_priv *uc_priv) linkmap = uc_priv->link_port_map; - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + for (i = 0; i < uc_priv->n_ports; i++) { if (((linkmap >> i) & 0x01)) { if (ahci_port_start(uc_priv, (u8) i)) { printf("Can not start port %d\n", i); diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 4d171f457e..8ab56d247d 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -216,6 +216,10 @@ static unsigned char mmc_board_init(struct mmc *mmc) /* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */ pbias_lite &= ~PBIASLITEVMODE0; #endif +#ifdef CONFIG_TARGET_OMAP3_LOGIC + /* For Logic PD board, 1.8V bias to go enable gpio127 for mmc_cd */ + pbias_lite &= ~PBIASLITEVMODE1; +#endif #ifdef CONFIG_MMC_OMAP36XX_PINS if (get_cpu_family() == CPU_OMAP36XX) { /* Disable extended drain IO before changing PBIAS */ diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index c31695eba9..8e2a48cfd6 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -1008,6 +1008,25 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) return 1; } +static void cpsw_phy_addr_update(struct cpsw_priv *priv) +{ + struct cpsw_platform_data *data = &priv->data; + u16 alive = mdio_regs->alive & GENMASK(15, 0); + int active = data->active_slave; + int new_addr = ffs(alive) - 1; + + /* + * If there is only one phy alive and its address does not match + * that of active slave, then phy address can safely be updated. + */ + if (hweight16(alive) == 1 && + data->slave_data[active].phy_addr != new_addr) { + printf("Updated phy address for CPSW#%d, old: %d, new: %d\n", + active, data->slave_data[active].phy_addr, new_addr); + data->slave_data[active].phy_addr = new_addr; + } +} + int _cpsw_register(struct cpsw_priv *priv) { struct cpsw_slave *slave; @@ -1034,6 +1053,9 @@ int _cpsw_register(struct cpsw_priv *priv) } cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div); + + cpsw_phy_addr_update(priv); + priv->bus = miiphy_get_dev_by_name(priv->dev->name); for_active_slave(slave, priv) cpsw_phy_init(priv, slave); @@ -1458,6 +1480,13 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) return 0; } +int cpsw_get_slave_phy_addr(struct udevice *dev, int slave) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + struct cpsw_platform_data *data = &priv->data; + + return data->slave_data[slave].phy_addr; +} static const struct udevice_id cpsw_eth_ids[] = { { .compatible = "ti,cpsw" }, diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c index 8955805e3b..8bf04f26a3 100644 --- a/drivers/rtc/pl031.c +++ b/drivers/rtc/pl031.c @@ -8,13 +8,11 @@ #include <common.h> #include <command.h> +#include <dm.h> +#include <errno.h> #include <rtc.h> - -#if defined(CONFIG_CMD_DATE) - -#ifndef CONFIG_SYS_RTC_PL031_BASE -#error CONFIG_SYS_RTC_PL031_BASE is not defined! -#endif +#include <asm/io.h> +#include <asm/types.h> /* * Register definitions @@ -30,78 +28,114 @@ #define RTC_CR_START (1 << 0) -#define RTC_WRITE_REG(addr, val) \ - (*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)) = (val)) -#define RTC_READ_REG(addr) \ - (*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr))) +struct pl031_platdata { + phys_addr_t base; +}; -static int pl031_initted = 0; +static inline u32 pl031_read_reg(struct udevice *dev, int reg) +{ + struct pl031_platdata *pdata = dev_get_platdata(dev); -/* Enable RTC Start in Control register*/ -void rtc_init(void) + return readl(pdata->base + reg); +} + +static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value) { - RTC_WRITE_REG(RTC_CR, RTC_CR_START); + struct pl031_platdata *pdata = dev_get_platdata(dev); - pl031_initted = 1; + return writel(value, pdata->base + reg); } /* - * Reset the RTC. We set the date back to 1970-01-01. + * Probe RTC device + */ +static int pl031_probe(struct udevice *dev) +{ + /* Enable RTC Start in Control register*/ + pl031_write_reg(dev, RTC_CR, RTC_CR_START); + + return 0; +} + +/* + * Get the current time from the RTC */ -void rtc_reset(void) +static int pl031_get(struct udevice *dev, struct rtc_time *tm) { - RTC_WRITE_REG(RTC_LR, 0x00); - if(!pl031_initted) - rtc_init(); + unsigned long tim; + + if (!tm) + return -EINVAL; + + tim = pl031_read_reg(dev, RTC_DR); + + rtc_to_tm(tim, tm); + + debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; } /* * Set the RTC -*/ -int rtc_set(struct rtc_time *tmp) + */ +static int pl031_set(struct udevice *dev, const struct rtc_time *tm) { unsigned long tim; - if(!pl031_initted) - rtc_init(); + if (!tm) + return -EINVAL; - if (tmp == NULL) { - puts("Error setting the date/time\n"); - return -1; - } + debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); /* Calculate number of seconds this incoming time represents */ - tim = rtc_mktime(tmp); + tim = rtc_mktime(tm); - RTC_WRITE_REG(RTC_LR, tim); + pl031_write_reg(dev, RTC_LR, tim); - return -1; + return 0; } /* - * Get the current time from the RTC + * Reset the RTC. We set the date back to 1970-01-01. */ -int rtc_get(struct rtc_time *tmp) +static int pl031_reset(struct udevice *dev) { - ulong tim; + pl031_write_reg(dev, RTC_LR, 0); - if(!pl031_initted) - rtc_init(); + return 0; +} - if (tmp == NULL) { - puts("Error getting the date/time\n"); - return -1; - } +static const struct rtc_ops pl031_ops = { + .get = pl031_get, + .set = pl031_set, + .reset = pl031_reset, +}; - tim = RTC_READ_REG(RTC_DR); +static const struct udevice_id pl031_ids[] = { + { .compatible = "arm,pl031" }, + { } +}; - rtc_to_tm(tim, tmp); +static int pl031_ofdata_to_platdata(struct udevice *dev) +{ + struct pl031_platdata *pdata = dev_get_platdata(dev); - debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + pdata->base = dev_read_addr(dev); return 0; } -#endif +U_BOOT_DRIVER(rtc_pl031) = { + .name = "rtc-pl031", + .id = UCLASS_RTC, + .of_match = pl031_ids, + .probe = pl031_probe, + .ofdata_to_platdata = pl031_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct pl031_platdata), + .ops = &pl031_ops, +}; diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index 399dfd65fe..1b54d1880f 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -17,7 +17,7 @@ /* Information about the efi console */ struct serial_efi_priv { - struct efi_simple_input_interface *con_in; + struct efi_simple_text_input_protocol *con_in; struct efi_simple_text_output_protocol *con_out; struct efi_input_key key; bool have_key; diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c index d8a047bb71..af3c755f96 100644 --- a/drivers/serial/serial_omap.c +++ b/drivers/serial/serial_omap.c @@ -104,6 +104,7 @@ static const struct udevice_id omap_serial_ids[] = { { .compatible = "ti,am3352-uart", }, { .compatible = "ti,am4372-uart", }, { .compatible = "ti,dra742-uart", }, + { .compatible = "ti,am654-uart", }, {} }; #endif /* OF_CONTROL && !OF_PLATDATA */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index dcd719ff0a..7d4d47da4b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -125,6 +125,14 @@ config PIC32_SPI to access the SPI NOR flash, MMC-over-SPI on platforms based on Microchip PIC32 family devices. +config PL022_SPI + bool "ARM AMBA PL022 SSP controller driver" + depends on ARM + help + This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP + controller. If you have an embedded system with an AMBA(R) + bus and a PL022 controller, say Y or M here. + config RENESAS_RPC_SPI bool "Renesas RPC SPI driver" depends on RCAR_GEN3 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 728e30c538..6679987cad 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MXS_SPI) += mxs_spi.o obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o obj-$(CONFIG_PIC32_SPI) += pic32_spi.o +obj-$(CONFIG_PL022_SPI) += pl022_spi.o obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c new file mode 100644 index 0000000000..86b71d2e21 --- /dev/null +++ b/drivers/spi/pl022_spi.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2012 + * Armando Visconti, ST Microelectronics, armando.visconti@st.com. + * + * (C) Copyright 2018 + * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com + * + * Driver for ARM PL022 SPI Controller. + */ + +#include <asm/io.h> +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <dm/platform_data/pl022_spi.h> +#include <fdtdec.h> +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <spi.h> + +#define SSP_CR0 0x000 +#define SSP_CR1 0x004 +#define SSP_DR 0x008 +#define SSP_SR 0x00C +#define SSP_CPSR 0x010 +#define SSP_IMSC 0x014 +#define SSP_RIS 0x018 +#define SSP_MIS 0x01C +#define SSP_ICR 0x020 +#define SSP_DMACR 0x024 +#define SSP_CSR 0x030 /* vendor extension */ +#define SSP_ITCR 0x080 +#define SSP_ITIP 0x084 +#define SSP_ITOP 0x088 +#define SSP_TDR 0x08C + +#define SSP_PID0 0xFE0 +#define SSP_PID1 0xFE4 +#define SSP_PID2 0xFE8 +#define SSP_PID3 0xFEC + +#define SSP_CID0 0xFF0 +#define SSP_CID1 0xFF4 +#define SSP_CID2 0xFF8 +#define SSP_CID3 0xFFC + +/* SSP Control Register 0 - SSP_CR0 */ +#define SSP_CR0_SPO (0x1 << 6) +#define SSP_CR0_SPH (0x1 << 7) +#define SSP_CR0_BIT_MODE(x) ((x) - 1) +#define SSP_SCR_MIN (0x00) +#define SSP_SCR_MAX (0xFF) +#define SSP_SCR_SHFT 8 +#define DFLT_CLKRATE 2 + +/* SSP Control Register 1 - SSP_CR1 */ +#define SSP_CR1_MASK_SSE (0x1 << 1) + +#define SSP_CPSR_MIN (0x02) +#define SSP_CPSR_MAX (0xFE) +#define DFLT_PRESCALE (0x40) + +/* SSP Status Register - SSP_SR */ +#define SSP_SR_MASK_TFE (0x1 << 0) /* Transmit FIFO empty */ +#define SSP_SR_MASK_TNF (0x1 << 1) /* Transmit FIFO not full */ +#define SSP_SR_MASK_RNE (0x1 << 2) /* Receive FIFO not empty */ +#define SSP_SR_MASK_RFF (0x1 << 3) /* Receive FIFO full */ +#define SSP_SR_MASK_BSY (0x1 << 4) /* Busy Flag */ + +struct pl022_spi_slave { + void *base; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct clk clk; +#else + unsigned int freq; +#endif +}; + +/* + * ARM PL022 exists in different 'flavors'. + * This drivers currently support the standard variant (0x00041022), that has a + * 16bit wide and 8 locations deep TX/RX FIFO. + */ +static int pl022_is_supported(struct pl022_spi_slave *ps) +{ + /* PL022 version is 0x00041022 */ + if ((readw(ps->base + SSP_PID0) == 0x22) && + (readw(ps->base + SSP_PID1) == 0x10) && + ((readw(ps->base + SSP_PID2) & 0xf) == 0x04) && + (readw(ps->base + SSP_PID3) == 0x00)) + return 1; + + return 0; +} + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +static int pl022_spi_ofdata_to_platdata(struct udevice *bus) +{ + struct pl022_spi_pdata *plat = bus->platdata; + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(bus); + + plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size); + + return clk_get_by_index(bus, 0, &plat->clk); +} +#endif + +static int pl022_spi_probe(struct udevice *bus) +{ + struct pl022_spi_pdata *plat = dev_get_platdata(bus); + struct pl022_spi_slave *ps = dev_get_priv(bus); + + ps->base = ioremap(plat->addr, plat->size); +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + ps->clk = plat->clk; +#else + ps->freq = plat->freq; +#endif + + /* Check the PL022 version */ + if (!pl022_is_supported(ps)) + return -ENOTSUPP; + + /* 8 bits per word, high polarity and default clock rate */ + writew(SSP_CR0_BIT_MODE(8), ps->base + SSP_CR0); + writew(DFLT_PRESCALE, ps->base + SSP_CPSR); + + return 0; +} + +static void flush(struct pl022_spi_slave *ps) +{ + do { + while (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) + readw(ps->base + SSP_DR); + } while (readw(ps->base + SSP_SR) & SSP_SR_MASK_BSY); +} + +static int pl022_spi_claim_bus(struct udevice *dev) +{ + struct udevice *bus = dev->parent; + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 reg; + + /* Enable the SPI hardware */ + reg = readw(ps->base + SSP_CR1); + reg |= SSP_CR1_MASK_SSE; + writew(reg, ps->base + SSP_CR1); + + flush(ps); + + return 0; +} + +static int pl022_spi_release_bus(struct udevice *dev) +{ + struct udevice *bus = dev->parent; + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 reg; + + flush(ps); + + /* Disable the SPI hardware */ + reg = readw(ps->base + SSP_CR1); + reg &= ~SSP_CR1_MASK_SSE; + writew(reg, ps->base + SSP_CR1); + + return 0; +} + +static int pl022_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct pl022_spi_slave *ps = dev_get_priv(bus); + u32 len_tx = 0, len_rx = 0, len; + u32 ret = 0; + const u8 *txp = dout; + u8 *rxp = din, value; + + if (bitlen == 0) + /* Finish any previously submitted transfers */ + return 0; + + /* + * TODO: The controller can do non-multiple-of-8 bit + * transfers, but this driver currently doesn't support it. + * + * It's also not clear how such transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + return -1; + } + + len = bitlen / 8; + + while (len_tx < len) { + if (readw(ps->base + SSP_SR) & SSP_SR_MASK_TNF) { + value = txp ? *txp++ : 0; + writew(value, ps->base + SSP_DR); + len_tx++; + } + + if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) { + value = readw(ps->base + SSP_DR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + + while (len_rx < len_tx) { + if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) { + value = readw(ps->base + SSP_DR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + + return ret; +} + +static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr) +{ + return rate / (cpsdvsr * (1 + scr)); +} + +static int pl022_spi_set_speed(struct udevice *bus, uint speed) +{ + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr, + best_cpsr = cpsr; + u32 min, max, best_freq = 0, tmp; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + u32 rate = clk_get_rate(&ps->clk); +#else + u32 rate = ps->freq; +#endif + bool found = false; + + max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN); + min = spi_rate(rate, SSP_CPSR_MAX, SSP_SCR_MAX); + + if (speed > max || speed < min) { + pr_err("Tried to set speed to %dHz but min=%d and max=%d\n", + speed, min, max); + return -EINVAL; + } + + while (cpsr <= SSP_CPSR_MAX && !found) { + while (scr <= SSP_SCR_MAX) { + tmp = spi_rate(rate, cpsr, scr); + + if (abs(speed - tmp) < abs(speed - best_freq)) { + best_freq = tmp; + best_cpsr = cpsr; + best_scr = scr; + + if (tmp == speed) { + found = true; + break; + } + } + + scr++; + } + cpsr += 2; + scr = SSP_SCR_MIN; + } + + writew(best_cpsr, ps->base + SSP_CPSR); + cr0 = readw(ps->base + SSP_CR0); + writew(cr0 | (best_scr << SSP_SCR_SHFT), ps->base + SSP_CR0); + + return 0; +} + +static int pl022_spi_set_mode(struct udevice *bus, uint mode) +{ + struct pl022_spi_slave *ps = dev_get_priv(bus); + u16 reg; + + reg = readw(ps->base + SSP_CR0); + reg &= ~(SSP_CR0_SPH | SSP_CR0_SPO); + if (mode & SPI_CPHA) + reg |= SSP_CR0_SPH; + if (mode & SPI_CPOL) + reg |= SSP_CR0_SPO; + writew(reg, ps->base + SSP_CR0); + + return 0; +} + +static int pl022_cs_info(struct udevice *bus, uint cs, + struct spi_cs_info *info) +{ + return 0; +} + +static const struct dm_spi_ops pl022_spi_ops = { + .claim_bus = pl022_spi_claim_bus, + .release_bus = pl022_spi_release_bus, + .xfer = pl022_spi_xfer, + .set_speed = pl022_spi_set_speed, + .set_mode = pl022_spi_set_mode, + .cs_info = pl022_cs_info, +}; + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +static const struct udevice_id pl022_spi_ids[] = { + { .compatible = "arm,pl022-spi" }, + { } +}; +#endif + +U_BOOT_DRIVER(pl022_spi) = { + .name = "pl022_spi", + .id = UCLASS_SPI, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .of_match = pl022_spi_ids, +#endif + .ops = &pl022_spi_ops, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .ofdata_to_platdata = pl022_spi_ofdata_to_platdata, +#endif + .platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata), + .priv_auto_alloc_size = sizeof(struct pl022_spi_slave), + .probe = pl022_spi_probe, +}; diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index f1d3ad3611..0c36a5de0a 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -213,6 +213,14 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) s++; /* ; */ s = parsenum(s, &col); + /* + * Ensure we stay in the bounds of the screen. + */ + if (row >= priv->rows) + row = priv->rows - 1; + if (col >= priv->cols) + col = priv->cols - 1; + priv->ycur = row * priv->y_charsize; priv->xcur_frac = priv->xstart_frac + VID_TO_POS(col * priv->x_charsize); |