diff options
author | Stefano Babic <sbabic@denx.de> | 2017-05-09 18:03:44 +0200 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2017-05-09 18:03:44 +0200 |
commit | 4f66e09bb9fbc47b73f67c3cc08ee2663e8fcdb1 (patch) | |
tree | 89bc85aa5a8ca9b60027cdd2f1a40fc83f6278c4 /drivers | |
parent | 809b133722eee0e7bdfa6595daabc0bb2f5aa698 (diff) | |
parent | 85ea850976daea57c8045f3569566fad5ce9fe0f (diff) |
Merge branch 'master' of git://git.denx.de/u-boot
Signed-off-by: Stefano Babic <sbabic@denx.de>
Diffstat (limited to 'drivers')
103 files changed, 3566 insertions, 3525 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 3e6bbacd15..a096dad2b2 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -24,6 +24,8 @@ source "drivers/dfu/Kconfig" source "drivers/dma/Kconfig" +source "drivers/firmware/Kconfig" + source "drivers/fpga/Kconfig" source "drivers/gpio/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5d8baa5a1f..4a4b2377c5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_SPL_SERIAL_SUPPORT) += serial/ obj-$(CONFIG_SPL_SPI_SUPPORT) += spi/ obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/ obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/ -obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ +obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/ obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/ obj-$(CONFIG_SPL_NAND_SUPPORT) += mtd/nand/ obj-$(CONFIG_SPL_ONENAND_SUPPORT) += mtd/onenand/ @@ -52,7 +52,7 @@ endif ifdef CONFIG_TPL_BUILD obj-$(CONFIG_TPL_I2C_SUPPORT) += i2c/ -obj-$(CONFIG_TPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ +obj-$(CONFIG_TPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/ obj-$(CONFIG_TPL_MMC_SUPPORT) += mmc/ obj-$(CONFIG_TPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/ obj-$(CONFIG_TPL_NAND_SUPPORT) += mtd/nand/ @@ -71,6 +71,7 @@ obj-y += block/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ +obj-y += firmware/ obj-$(CONFIG_FPGA) += fpga/ obj-y += hwmon/ obj-y += misc/ diff --git a/drivers/block/Makefile b/drivers/block/Makefile index a72feecd54..f415b3371b 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_IDE_FTIDE020) += ftide020.o obj-$(CONFIG_LIBATA) += libata.o obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o obj-$(CONFIG_MX51_PATA) += mxc_ata.o -obj-$(CONFIG_PATA_BFIN) += pata_bfin.o obj-$(CONFIG_SATA_CEVA) += sata_ceva.o obj-$(CONFIG_SATA_DWC) += sata_dwc.o obj-$(CONFIG_SATA_MV) += sata_mv.o diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c index e000ebff76..31f7fab8b4 100644 --- a/drivers/block/fsl_sata.c +++ b/drivers/block/fsl_sata.c @@ -124,7 +124,7 @@ int init_sata(int dev) length = sizeof(struct cmd_hdr_tbl); align = SATA_HC_CMD_HDR_TBL_ALIGN; sata->cmd_hdr_tbl_offset = (void *)malloc(length + align); - if (!sata) { + if (!sata->cmd_hdr_tbl_offset) { printf("alloc the command header failed\n\r"); return -1; } diff --git a/drivers/block/pata_bfin.c b/drivers/block/pata_bfin.c deleted file mode 100644 index 36a15125ad..0000000000 --- a/drivers/block/pata_bfin.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * Driver for Blackfin on-chip ATAPI controller. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Copyright (c) 2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <command.h> -#include <config.h> -#include <asm/byteorder.h> -#include <asm/clock.h> -#include <asm/io.h> -#include <linux/errno.h> -#include <asm/portmux.h> -#include <asm/mach-common/bits/pata.h> -#include <ata.h> -#include <sata.h> -#include <libata.h> -#include "pata_bfin.h" - -static struct ata_port port[CONFIG_SYS_SATA_MAX_DEVICE]; - -/** - * PIO Mode - Frequency compatibility - */ -/* mode: 0 1 2 3 4 */ -static const u32 pio_fsclk[] = -{ 33333333, 33333333, 33333333, 33333333, 33333333 }; - -/** - * MDMA Mode - Frequency compatibility - */ -/* mode: 0 1 2 */ -static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 }; - -/** - * UDMA Mode - Frequency compatibility - * - * UDMA5 - 100 MB/s - SCLK = 133 MHz - * UDMA4 - 66 MB/s - SCLK >= 80 MHz - * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz - * UDMA2 - 33 MB/s - SCLK >= 40 MHz - */ -/* mode: 0 1 2 3 4 5 */ -static const u32 udma_fsclk[] = -{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 }; - -/** - * Register transfer timing table - */ -/* mode: 0 1 2 3 4 */ -/* Cycle Time */ -static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 }; -/* DIOR/DIOW to end cycle */ -static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 }; -/* DIOR/DIOW asserted pulse width */ -static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 }; - -/** - * PIO timing table - */ -/* mode: 0 1 2 3 4 */ -/* Cycle Time */ -static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 }; -/* Address valid to DIOR/DIORW */ -static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 }; -/* DIOR/DIOW to end cycle */ -static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 }; -/* DIOR/DIOW asserted pulse width */ -static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 }; -/* DIOW data hold */ -static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 }; - -/* ****************************************************************** - * Multiword DMA timing table - * ****************************************************************** - */ -/* mode: 0 1 2 */ -/* Cycle Time */ -static const u32 mdma_t0min[] = { 480, 150, 120 }; -/* DIOR/DIOW asserted pulse width */ -static const u32 mdma_tdmin[] = { 215, 80, 70 }; -/* DMACK to read data released */ -static const u32 mdma_thmin[] = { 20, 15, 10 }; -/* DIOR/DIOW to DMACK hold */ -static const u32 mdma_tjmin[] = { 20, 5, 5 }; -/* DIOR negated pulse width */ -static const u32 mdma_tkrmin[] = { 50, 50, 25 }; -/* DIOR negated pulse width */ -static const u32 mdma_tkwmin[] = { 215, 50, 25 }; -/* CS[1:0] valid to DIOR/DIOW */ -static const u32 mdma_tmmin[] = { 50, 30, 25 }; -/* DMACK to read data released */ -static const u32 mdma_tzmax[] = { 20, 25, 25 }; - -/** - * Ultra DMA timing table - */ -/* mode: 0 1 2 3 4 5 */ -static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 }; -static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 }; -static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 }; -static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 }; -static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 }; - - -static const u32 udma_tmlimin = 20; -static const u32 udma_tzahmin = 20; -static const u32 udma_tenvmin = 20; -static const u32 udma_tackmin = 20; -static const u32 udma_tssmin = 50; - -static void msleep(int count) -{ - int i; - - for (i = 0; i < count; i++) - udelay(1000); -} - -/** - * - * Function: num_clocks_min - * - * Description: - * calculate number of SCLK cycles to meet minimum timing - */ -static unsigned short num_clocks_min(unsigned long tmin, - unsigned long fsclk) -{ - unsigned long tmp ; - unsigned short result; - - tmp = tmin * (fsclk/1000/1000) / 1000; - result = (unsigned short)tmp; - if ((tmp*1000*1000) < (tmin*(fsclk/1000))) - result++; - - return result; -} - -/** - * bfin_set_piomode - Initialize host controller PATA PIO timings - * @ap: Port whose timings we are configuring - * @pio_mode: mode - * - * Set PIO mode for device. - * - * LOCKING: - * None (inherited from caller). - */ - -static void bfin_set_piomode(struct ata_port *ap, int pio_mode) -{ - int mode = pio_mode - XFER_PIO_0; - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - unsigned int fsclk = get_sclk(); - unsigned short teoc_reg, t2_reg, teoc_pio; - unsigned short t4_reg, t2_pio, t1_reg; - unsigned short n0, n6, t6min = 5; - - /* the most restrictive timing value is t6 and tc, the DIOW - data hold - * If one SCLK pulse is longer than this minimum value then register - * transfers cannot be supported at this frequency. - */ - n6 = num_clocks_min(t6min, fsclk); - if (mode >= 0 && mode <= 4 && n6 >= 1) { - debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); - /* calculate the timing values for register transfers. */ - while (mode > 0 && pio_fsclk[mode] > fsclk) - mode--; - - /* DIOR/DIOW to end cycle time */ - t2_reg = num_clocks_min(reg_t2min[mode], fsclk); - /* DIOR/DIOW asserted pulse width */ - teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk); - /* Cycle Time */ - n0 = num_clocks_min(reg_t0min[mode], fsclk); - - /* increase t2 until we meed the minimum cycle length */ - if (t2_reg + teoc_reg < n0) - t2_reg = n0 - teoc_reg; - - /* calculate the timing values for pio transfers. */ - - /* DIOR/DIOW to end cycle time */ - t2_pio = num_clocks_min(pio_t2min[mode], fsclk); - /* DIOR/DIOW asserted pulse width */ - teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk); - /* Cycle Time */ - n0 = num_clocks_min(pio_t0min[mode], fsclk); - - /* increase t2 until we meed the minimum cycle length */ - if (t2_pio + teoc_pio < n0) - t2_pio = n0 - teoc_pio; - - /* Address valid to DIOR/DIORW */ - t1_reg = num_clocks_min(pio_t1min[mode], fsclk); - - /* DIOW data hold */ - t4_reg = num_clocks_min(pio_t4min[mode], fsclk); - - ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg)); - ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg)); - ATAPI_SET_PIO_TIM_1(base, teoc_pio); - if (mode > 2) { - ATAPI_SET_CONTROL(base, - ATAPI_GET_CONTROL(base) | IORDY_EN); - } else { - ATAPI_SET_CONTROL(base, - ATAPI_GET_CONTROL(base) & ~IORDY_EN); - } - - /* Disable host ATAPI PIO interrupts */ - ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) - & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK)); - SSYNC(); - } -} - -/** - * - * Function: wait_complete - * - * Description: Waits the interrupt from device - * - */ -static inline void wait_complete(void __iomem *base, unsigned short mask) -{ - unsigned short status; - unsigned int i = 0; - - for (i = 0; i < PATA_BFIN_WAIT_TIMEOUT; i++) { - status = ATAPI_GET_INT_STATUS(base) & mask; - if (status) - break; - } - - ATAPI_SET_INT_STATUS(base, mask); -} - -/** - * - * Function: write_atapi_register - * - * Description: Writes to ATA Device Resgister - * - */ - -static void write_atapi_register(void __iomem *base, - unsigned long ata_reg, unsigned short value) -{ - /* Program the ATA_DEV_TXBUF register with write data (to be - * written into the device). - */ - ATAPI_SET_DEV_TXBUF(base, value); - - /* Program the ATA_DEV_ADDR register with address of the - * device register (0x01 to 0x0F). - */ - ATAPI_SET_DEV_ADDR(base, ata_reg); - - /* Program the ATA_CTRL register with dir set to write (1) - */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); - - /* ensure PIO DMA is not set */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); - - /* and start the transfer */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); - - /* Wait for the interrupt to indicate the end of the transfer. - * (We need to wait on and clear rhe ATA_DEV_INT interrupt status) - */ - wait_complete(base, PIO_DONE_INT); -} - -/** - * - * Function: read_atapi_register - * - *Description: Reads from ATA Device Resgister - * - */ - -static unsigned short read_atapi_register(void __iomem *base, - unsigned long ata_reg) -{ - /* Program the ATA_DEV_ADDR register with address of the - * device register (0x01 to 0x0F). - */ - ATAPI_SET_DEV_ADDR(base, ata_reg); - - /* Program the ATA_CTRL register with dir set to read (0) and - */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); - - /* ensure PIO DMA is not set */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); - - /* and start the transfer */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); - - /* Wait for the interrupt to indicate the end of the transfer. - * (PIO_DONE interrupt is set and it doesn't seem to matter - * that we don't clear it) - */ - wait_complete(base, PIO_DONE_INT); - - /* Read the ATA_DEV_RXBUF register with write data (to be - * written into the device). - */ - return ATAPI_GET_DEV_RXBUF(base); -} - -/** - * - * Function: write_atapi_register_data - * - * Description: Writes to ATA Device Resgister - * - */ - -static void write_atapi_data(void __iomem *base, - int len, unsigned short *buf) -{ - int i; - - /* Set transfer length to 1 */ - ATAPI_SET_XFER_LEN(base, 1); - - /* Program the ATA_DEV_ADDR register with address of the - * ATA_REG_DATA - */ - ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); - - /* Program the ATA_CTRL register with dir set to write (1) - */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); - - /* ensure PIO DMA is not set */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); - - for (i = 0; i < len; i++) { - /* Program the ATA_DEV_TXBUF register with write data (to be - * written into the device). - */ - ATAPI_SET_DEV_TXBUF(base, buf[i]); - - /* and start the transfer */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); - - /* Wait for the interrupt to indicate the end of the transfer. - * (We need to wait on and clear rhe ATA_DEV_INT - * interrupt status) - */ - wait_complete(base, PIO_DONE_INT); - } -} - -/** - * - * Function: read_atapi_register_data - * - * Description: Reads from ATA Device Resgister - * - */ - -static void read_atapi_data(void __iomem *base, - int len, unsigned short *buf) -{ - int i; - - /* Set transfer length to 1 */ - ATAPI_SET_XFER_LEN(base, 1); - - /* Program the ATA_DEV_ADDR register with address of the - * ATA_REG_DATA - */ - ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); - - /* Program the ATA_CTRL register with dir set to read (0) and - */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); - - /* ensure PIO DMA is not set */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); - - for (i = 0; i < len; i++) { - /* and start the transfer */ - ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); - - /* Wait for the interrupt to indicate the end of the transfer. - * (PIO_DONE interrupt is set and it doesn't seem to matter - * that we don't clear it) - */ - wait_complete(base, PIO_DONE_INT); - - /* Read the ATA_DEV_RXBUF register with write data (to be - * written into the device). - */ - buf[i] = ATAPI_GET_DEV_RXBUF(base); - } -} - -/** - * bfin_check_status - Read device status reg & clear interrupt - * @ap: port where the device is - * - * Note: Original code is ata_check_status(). - */ - -static u8 bfin_check_status(struct ata_port *ap) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - return read_atapi_register(base, ATA_REG_STATUS); -} - -/** - * bfin_check_altstatus - Read device alternate status reg - * @ap: port where the device is - */ - -static u8 bfin_check_altstatus(struct ata_port *ap) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - return read_atapi_register(base, ATA_REG_ALTSTATUS); -} - -/** - * bfin_ata_busy_wait - Wait for a port status register - * @ap: Port to wait for. - * @bits: bits that must be clear - * @max: number of 10uS waits to perform - * - * Waits up to max*10 microseconds for the selected bits in the port's - * status register to be cleared. - * Returns final value of status register. - * - * LOCKING: - * Inherited from caller. - */ -static inline u8 bfin_ata_busy_wait(struct ata_port *ap, unsigned int bits, - unsigned int max, u8 usealtstatus) -{ - u8 status; - - do { - udelay(10); - if (usealtstatus) - status = bfin_check_altstatus(ap); - else - status = bfin_check_status(ap); - max--; - } while (status != 0xff && (status & bits) && (max > 0)); - - return status; -} - -/** - * bfin_ata_busy_sleep - sleep until BSY clears, or timeout - * @ap: port containing status register to be polled - * @tmout_pat: impatience timeout in msecs - * @tmout: overall timeout in msecs - * - * Sleep until ATA Status register bit BSY clears, - * or a timeout occurs. - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -static int bfin_ata_busy_sleep(struct ata_port *ap, - long tmout_pat, unsigned long tmout) -{ - u8 status; - - status = bfin_ata_busy_wait(ap, ATA_BUSY, 300, 0); - while (status != 0xff && (status & ATA_BUSY) && tmout_pat > 0) { - msleep(50); - tmout_pat -= 50; - status = bfin_ata_busy_wait(ap, ATA_BUSY, 3, 0); - } - - if (status != 0xff && (status & ATA_BUSY)) - printf("port is slow to respond, please be patient " - "(Status 0x%x)\n", status); - - while (status != 0xff && (status & ATA_BUSY) && tmout_pat > 0) { - msleep(50); - tmout_pat -= 50; - status = bfin_check_status(ap); - } - - if (status == 0xff) - return -ENODEV; - - if (status & ATA_BUSY) { - printf("port failed to respond " - "(%lu secs, Status 0x%x)\n", - DIV_ROUND_UP(tmout, 1000), status); - return -EBUSY; - } - - return 0; -} - -/** - * bfin_dev_select - Select device 0/1 on ATA bus - * @ap: ATA channel to manipulate - * @device: ATA device (numbered from zero) to select - * - * Note: Original code is ata_sff_dev_select(). - */ - -static void bfin_dev_select(struct ata_port *ap, unsigned int device) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - u8 tmp; - - - if (device == 0) - tmp = ATA_DEVICE_OBS; - else - tmp = ATA_DEVICE_OBS | ATA_DEV1; - - write_atapi_register(base, ATA_REG_DEVICE, tmp); - udelay(1); -} - -/** - * bfin_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * Note: Original code is ata_devchk(). - */ - -static unsigned int bfin_devchk(struct ata_port *ap, - unsigned int device) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - u8 nsect, lbal; - - bfin_dev_select(ap, device); - - write_atapi_register(base, ATA_REG_NSECT, 0x55); - write_atapi_register(base, ATA_REG_LBAL, 0xaa); - - write_atapi_register(base, ATA_REG_NSECT, 0xaa); - write_atapi_register(base, ATA_REG_LBAL, 0x55); - - write_atapi_register(base, ATA_REG_NSECT, 0x55); - write_atapi_register(base, ATA_REG_LBAL, 0xaa); - - nsect = read_atapi_register(base, ATA_REG_NSECT); - lbal = read_atapi_register(base, ATA_REG_LBAL); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return 1; /* we found a device */ - - return 0; /* nothing found */ -} - -/** - * bfin_bus_post_reset - PATA device post reset - * - * Note: Original code is ata_bus_post_reset(). - */ - -static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - unsigned int dev0 = devmask & (1 << 0); - unsigned int dev1 = devmask & (1 << 1); - long deadline; - - /* if device 0 was found in ata_devchk, wait for its - * BSY bit to clear - */ - if (dev0) - bfin_ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); - - /* if device 1 was found in ata_devchk, wait for - * register access, then wait for BSY to clear - */ - deadline = ATA_TMOUT_BOOT; - while (dev1) { - u8 nsect, lbal; - - bfin_dev_select(ap, 1); - nsect = read_atapi_register(base, ATA_REG_NSECT); - lbal = read_atapi_register(base, ATA_REG_LBAL); - if ((nsect == 1) && (lbal == 1)) - break; - if (deadline <= 0) { - dev1 = 0; - break; - } - msleep(50); /* give drive a breather */ - deadline -= 50; - } - if (dev1) - bfin_ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); - - /* is all this really necessary? */ - bfin_dev_select(ap, 0); - if (dev1) - bfin_dev_select(ap, 1); - if (dev0) - bfin_dev_select(ap, 0); -} - -/** - * bfin_bus_softreset - PATA device software reset - * - * Note: Original code is ata_bus_softreset(). - */ - -static unsigned int bfin_bus_softreset(struct ata_port *ap, - unsigned int devmask) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - - /* software reset. causes dev0 to be selected */ - write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg); - udelay(20); - write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg | ATA_SRST); - udelay(20); - write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg); - - /* spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - * - * Old drivers/ide uses the 2mS rule and then waits for ready - */ - msleep(150); - - /* Before we perform post reset processing we want to see if - * the bus shows 0xFF because the odd clown forgets the D7 - * pulldown resistor. - */ - if (bfin_check_status(ap) == 0xFF) - return 0; - - bfin_bus_post_reset(ap, devmask); - - return 0; -} - -/** - * bfin_softreset - reset host port via ATA SRST - * @ap: port to reset - * - * Note: Original code is ata_sff_softreset(). - */ - -static int bfin_softreset(struct ata_port *ap) -{ - unsigned int err_mask; - - ap->dev_mask = 0; - - /* determine if device 0/1 are present. - * only one device is supported on one port by now. - */ - if (bfin_devchk(ap, 0)) - ap->dev_mask |= (1 << 0); - else if (bfin_devchk(ap, 1)) - ap->dev_mask |= (1 << 1); - else - return -ENODEV; - - /* select device 0 again */ - bfin_dev_select(ap, 0); - - /* issue bus reset */ - err_mask = bfin_bus_softreset(ap, ap->dev_mask); - if (err_mask) { - printf("SRST failed (err_mask=0x%x)\n", - err_mask); - ap->dev_mask = 0; - return -EIO; - } - - return 0; -} - -/** - * bfin_irq_clear - Clear ATAPI interrupt. - * @ap: Port associated with this ATA transaction. - * - * Note: Original code is ata_sff_irq_clear(). - */ - -static void bfin_irq_clear(struct ata_port *ap) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - - ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT - | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT - | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT); -} - -static u8 bfin_wait_for_irq(struct ata_port *ap, unsigned int max) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - - do { - if (ATAPI_GET_INT_STATUS(base) & (ATAPI_DEV_INT - | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT - | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT)) { - break; - } - udelay(1000); - max--; - } while ((max > 0)); - - return max == 0; -} - -/** - * bfin_ata_reset_port - initialize BFIN ATAPI port. - */ - -static int bfin_ata_reset_port(struct ata_port *ap) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - int count; - unsigned short status; - - /* Disable all ATAPI interrupts */ - ATAPI_SET_INT_MASK(base, 0); - SSYNC(); - - /* Assert the RESET signal 25us*/ - ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST); - udelay(30); - - /* Negate the RESET signal for 2ms*/ - ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST); - msleep(2); - - /* Wait on Busy flag to clear */ - count = 10000000; - do { - status = read_atapi_register(base, ATA_REG_STATUS); - } while (--count && (status & ATA_BUSY)); - - /* Enable only ATAPI Device interrupt */ - ATAPI_SET_INT_MASK(base, 1); - SSYNC(); - - return !count; -} - -/** - * - * Function: bfin_config_atapi_gpio - * - * Description: Configures the ATAPI pins for use - * - */ -static int bfin_config_atapi_gpio(struct ata_port *ap) -{ - const unsigned short pins[] = { - P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0, - P_ATAPI_CS1, P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ, - P_ATAPI_IORDY, P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A, - P_ATAPI_D3A, P_ATAPI_D4A, P_ATAPI_D5A, P_ATAPI_D6A, - P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A, P_ATAPI_D10A, - P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A, - P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A, 0, - }; - - peripheral_request_list(pins, "pata_bfin"); - - return 0; -} - -/** - * bfin_atapi_probe - attach a bfin atapi interface - * @pdev: platform device - * - * Register a bfin atapi interface. - * - * - * Platform devices are expected to contain 2 resources per port: - * - * - I/O Base (IORESOURCE_IO) - * - IRQ (IORESOURCE_IRQ) - * - */ -static int bfin_ata_probe_port(struct ata_port *ap) -{ - if (bfin_config_atapi_gpio(ap)) { - printf("Requesting Peripherals faild\n"); - return -EFAULT; - } - - if (bfin_ata_reset_port(ap)) { - printf("Fail to reset ATAPI device\n"); - return -EFAULT; - } - - if (ap->ata_mode >= XFER_PIO_0 && ap->ata_mode <= XFER_PIO_4) - bfin_set_piomode(ap, ap->ata_mode); - else { - printf("Given ATA data transfer mode is not supported.\n"); - return -EFAULT; - } - - return 0; -} - -#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) - -static void bfin_ata_identify(struct ata_port *ap, int dev) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - u8 status = 0; - static u16 iobuf[ATA_SECTOR_WORDS]; - u64 n_sectors = 0; - hd_driveid_t *iop = (hd_driveid_t *)iobuf; - - memset(iobuf, 0, sizeof(iobuf)); - - if (!(ap->dev_mask & (1 << dev))) - return; - - debug("port=%d dev=%d\n", ap->port_no, dev); - - bfin_dev_select(ap, dev); - - status = 0; - /* Device Identify Command */ - write_atapi_register(base, ATA_REG_CMD, ATA_CMD_ID_ATA); - bfin_check_altstatus(ap); - udelay(10); - - status = bfin_ata_busy_wait(ap, ATA_BUSY, 1000, 0); - if (status & ATA_ERR) { - printf("\ndevice not responding\n"); - ap->dev_mask &= ~(1 << dev); - return; - } - - read_atapi_data(base, ATA_SECTOR_WORDS, iobuf); - - ata_swap_buf_le16(iobuf, ATA_SECTOR_WORDS); - - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(iobuf) || !ata_id_has_lba(iobuf)) - printf("ata%u: no dma/lba\n", ap->port_no); - -#ifdef DEBUG - ata_dump_id(iobuf); -#endif - - n_sectors = ata_id_n_sectors(iobuf); - - if (n_sectors == 0) { - ap->dev_mask &= ~(1 << dev); - return; - } - - ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].revision, - ATA_ID_FW_REV, sizeof(sata_dev_desc[ap->port_no].revision)); - ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].vendor, - ATA_ID_PROD, sizeof(sata_dev_desc[ap->port_no].vendor)); - ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].product, - ATA_ID_SERNO, sizeof(sata_dev_desc[ap->port_no].product)); - - if ((iop->config & 0x0080) == 0x0080) - sata_dev_desc[ap->port_no].removable = 1; - else - sata_dev_desc[ap->port_no].removable = 0; - - sata_dev_desc[ap->port_no].lba = (u32) n_sectors; - debug("lba=0x%lx\n", sata_dev_desc[ap->port_no].lba); - -#ifdef CONFIG_LBA48 - if (iop->command_set_2 & 0x0400) - sata_dev_desc[ap->port_no].lba48 = 1; - else - sata_dev_desc[ap->port_no].lba48 = 0; -#endif - - /* assuming HD */ - sata_dev_desc[ap->port_no].type = DEV_TYPE_HARDDISK; - sata_dev_desc[ap->port_no].blksz = ATA_SECT_SIZE; - sata_dev_desc[ap->port_no].log2blksz = - LOG2(sata_dev_desc[ap->port_no].blksz); - sata_dev_desc[ap->port_no].lun = 0; /* just to fill something in... */ - - printf("PATA device#%d %s is found on ata port#%d.\n", - ap->port_no%PATA_DEV_NUM_PER_PORT, - sata_dev_desc[ap->port_no].vendor, - ap->port_no/PATA_DEV_NUM_PER_PORT); -} - -static void bfin_ata_set_Feature_cmd(struct ata_port *ap, int dev) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - u8 status = 0; - - if (!(ap->dev_mask & (1 << dev))) - return; - - bfin_dev_select(ap, dev); - - write_atapi_register(base, ATA_REG_FEATURE, SETFEATURES_XFER); - write_atapi_register(base, ATA_REG_NSECT, ap->ata_mode); - write_atapi_register(base, ATA_REG_LBAL, 0); - write_atapi_register(base, ATA_REG_LBAM, 0); - write_atapi_register(base, ATA_REG_LBAH, 0); - - write_atapi_register(base, ATA_REG_DEVICE, ATA_DEVICE_OBS); - write_atapi_register(base, ATA_REG_CMD, ATA_CMD_SET_FEATURES); - - udelay(50); - msleep(150); - - status = bfin_ata_busy_wait(ap, ATA_BUSY, 5000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf("Error : status 0x%02x\n", status); - ap->dev_mask &= ~(1 << dev); - } -} - -int scan_sata(int dev) -{ - /* dev is the index of each ata device in the system. one PATA port - * contains 2 devices. one element in scan_done array indicates one - * PATA port. device connected to one PATA port is selected by - * bfin_dev_select() before access. - */ - struct ata_port *ap = &port[dev]; - static int scan_done[(CONFIG_SYS_SATA_MAX_DEVICE+1)/PATA_DEV_NUM_PER_PORT]; - - if (scan_done[dev/PATA_DEV_NUM_PER_PORT]) - return 0; - - /* Check for attached device */ - if (!bfin_ata_probe_port(ap)) { - if (bfin_softreset(ap)) { - /* soft reset failed, try a hard one */ - bfin_ata_reset_port(ap); - if (bfin_softreset(ap)) - scan_done[dev/PATA_DEV_NUM_PER_PORT] = 1; - } else { - scan_done[dev/PATA_DEV_NUM_PER_PORT] = 1; - } - } - if (scan_done[dev/PATA_DEV_NUM_PER_PORT]) { - /* Probe device and set xfer mode */ - bfin_ata_identify(ap, dev%PATA_DEV_NUM_PER_PORT); - bfin_ata_set_Feature_cmd(ap, dev%PATA_DEV_NUM_PER_PORT); - part_init(&sata_dev_desc[dev]); - return 0; - } - - printf("PATA device#%d is not present on ATA port#%d.\n", - ap->port_no%PATA_DEV_NUM_PER_PORT, - ap->port_no/PATA_DEV_NUM_PER_PORT); - - return -1; -} - -int init_sata(int dev) -{ - struct ata_port *ap = &port[dev]; - static u8 init_done; - int res = 1; - - if (init_done) - return res; - - init_done = 1; - - switch (dev/PATA_DEV_NUM_PER_PORT) { - case 0: - ap->ioaddr.ctl_addr = ATAPI_CONTROL; - ap->ata_mode = CONFIG_BFIN_ATA_MODE; - break; - default: - printf("Tried to scan unknown port %d.\n", dev); - return res; - } - - if (ap->ata_mode < XFER_PIO_0 || ap->ata_mode > XFER_PIO_4) { - ap->ata_mode = XFER_PIO_4; - printf("DMA mode is not supported. Set to PIO mode 4.\n"); - } - - ap->port_no = dev; - ap->ctl_reg = 0x8; /*Default value of control reg */ - - res = 0; - return res; -} - -int reset_sata(int dev) -{ - return 0; -} - -/* Read up to 255 sectors - * - * Returns sectors read -*/ -static u8 do_one_read(struct ata_port *ap, u64 blknr, u8 blkcnt, u16 *buffer, - uchar lba48) -{ - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - u8 sr = 0; - u8 status; - u16 err = 0; - - if (!(bfin_check_status(ap) & ATA_DRDY)) { - printf("Device ata%d not ready\n", ap->port_no); - return 0; - } - - /* Set up transfer */ -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - write_atapi_register(base, ATA_REG_NSECT, 0); - write_atapi_register(base, ATA_REG_LBAL, (blknr >> 24) & 0xFF); - write_atapi_register(base, ATA_REG_LBAM, (blknr >> 32) & 0xFF); - write_atapi_register(base, ATA_REG_LBAH, (blknr >> 40) & 0xFF); - } -#endif - write_atapi_register(base, ATA_REG_NSECT, blkcnt); - write_atapi_register(base, ATA_REG_LBAL, (blknr >> 0) & 0xFF); - write_atapi_register(base, ATA_REG_LBAM, (blknr >> 8) & 0xFF); - write_atapi_register(base, ATA_REG_LBAH, (blknr >> 16) & 0xFF); - -#ifdef CONFIG_LBA48 - if (lba48) { - write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA); - write_atapi_register(base, ATA_REG_CMD, ATA_CMD_PIO_READ_EXT); - } else -#endif - { - write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA | ((blknr >> 24) & 0xF)); - write_atapi_register(base, ATA_REG_CMD, ATA_CMD_PIO_READ); - } - status = bfin_ata_busy_wait(ap, ATA_BUSY, 500000, 1); - - if (status & (ATA_BUSY | ATA_ERR)) { - printf("Device %d not responding status 0x%x.\n", ap->port_no, status); - err = read_atapi_register(base, ATA_REG_ERR); - printf("Error reg = 0x%x\n", err); - return sr; - } - - while (blkcnt--) { - if (bfin_wait_for_irq(ap, 500)) { - printf("ata%u irq failed\n", ap->port_no); - return sr; - } - - status = bfin_check_status(ap); - if (status & ATA_ERR) { - err = read_atapi_register(base, ATA_REG_ERR); - printf("ata%u error %d\n", ap->port_no, err); - return sr; - } - bfin_irq_clear(ap); - - /* Read one sector */ - read_atapi_data(base, ATA_SECTOR_WORDS, buffer); - buffer += ATA_SECTOR_WORDS; - sr++; - } - - return sr; -} - -ulong sata_read(int dev, ulong block, lbaint_t blkcnt, void *buff) -{ - struct ata_port *ap = &port[dev]; - ulong n = 0, sread; - u16 *buffer = (u16 *) buff; - u8 status = 0; - u64 blknr = (u64) block; - unsigned char lba48 = 0; - -#ifdef CONFIG_LBA48 - if (blknr > 0xfffffff) { - if (!sata_dev_desc[dev].lba48) { - printf("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - bfin_dev_select(ap, dev%PATA_DEV_NUM_PER_PORT); - - while (blkcnt > 0) { - - if (blkcnt > 255) - sread = 255; - else - sread = blkcnt; - - status = do_one_read(ap, blknr, sread, buffer, lba48); - if (status != sread) { - printf("Read failed\n"); - return n; - } - - blkcnt -= sread; - blknr += sread; - n += sread; - buffer += sread * ATA_SECTOR_WORDS; - } - return n; -} - -ulong sata_write(int dev, ulong block, lbaint_t blkcnt, const void *buff) -{ - struct ata_port *ap = &port[dev]; - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - ulong n = 0; - u16 *buffer = (u16 *) buff; - unsigned char status = 0; - u64 blknr = (u64) block; -#ifdef CONFIG_LBA48 - unsigned char lba48 = 0; - - if (blknr > 0xfffffff) { - if (!sata_dev_desc[dev].lba48) { - printf("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - - bfin_dev_select(ap, dev%PATA_DEV_NUM_PER_PORT); - - while (blkcnt-- > 0) { - status = bfin_ata_busy_wait(ap, ATA_BUSY, 50000, 0); - if (status & ATA_BUSY) { - printf("ata%u failed to respond\n", ap->port_no); - return n; - } -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - write_atapi_register(base, ATA_REG_NSECT, 0); - write_atapi_register(base, ATA_REG_LBAL, - (blknr >> 24) & 0xFF); - write_atapi_register(base, ATA_REG_LBAM, - (blknr >> 32) & 0xFF); - write_atapi_register(base, ATA_REG_LBAH, - (blknr >> 40) & 0xFF); - } -#endif - write_atapi_register(base, ATA_REG_NSECT, 1); - write_atapi_register(base, ATA_REG_LBAL, (blknr >> 0) & 0xFF); - write_atapi_register(base, ATA_REG_LBAM, (blknr >> 8) & 0xFF); - write_atapi_register(base, ATA_REG_LBAH, (blknr >> 16) & 0xFF); -#ifdef CONFIG_LBA48 - if (lba48) { - write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA); - write_atapi_register(base, ATA_REG_CMD, - ATA_CMD_PIO_WRITE_EXT); - } else -#endif - { - write_atapi_register(base, ATA_REG_DEVICE, - ATA_LBA | ((blknr >> 24) & 0xF)); - write_atapi_register(base, ATA_REG_CMD, - ATA_CMD_PIO_WRITE); - } - - /*may take up to 5 sec */ - status = bfin_ata_busy_wait(ap, ATA_BUSY, 50000, 0); - if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) { - printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", - ap->port_no, (ulong) blknr, status); - return n; - } - - write_atapi_data(base, ATA_SECTOR_WORDS, buffer); - bfin_check_altstatus(ap); - udelay(1); - - ++n; - ++blknr; - buffer += ATA_SECTOR_WORDS; - } - return n; -} diff --git a/drivers/block/pata_bfin.h b/drivers/block/pata_bfin.h deleted file mode 100644 index b678f60b2d..0000000000 --- a/drivers/block/pata_bfin.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Driver for Blackfin on-chip ATAPI controller. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Copyright (c) 2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef PATA_BFIN_H -#define PATA_BFIN_H - -#include <asm/blackfin_local.h> - -struct ata_ioports { - unsigned long cmd_addr; - unsigned long data_addr; - unsigned long error_addr; - unsigned long feature_addr; - unsigned long nsect_addr; - unsigned long lbal_addr; - unsigned long lbam_addr; - unsigned long lbah_addr; - unsigned long device_addr; - unsigned long status_addr; - unsigned long command_addr; - unsigned long altstatus_addr; - unsigned long ctl_addr; - unsigned long bmdma_addr; - unsigned long scr_addr; -}; - -struct ata_port { - unsigned int port_no; /* primary=0, secondary=1 */ - struct ata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ - unsigned long flag; - unsigned int ata_mode; - unsigned char ctl_reg; - unsigned char last_ctl; - unsigned char dev_mask; -}; - -#define DRV_NAME "pata-bfin" -#define DRV_VERSION "0.9" - -#define ATA_REG_CTRL 0x0E -#define ATA_REG_ALTSTATUS ATA_REG_CTRL -#define ATA_TMOUT_BOOT 30000 -#define ATA_TMOUT_BOOT_QUICK 7000 - -#define PATA_BFIN_WAIT_TIMEOUT 10000 -#define PATA_DEV_NUM_PER_PORT 2 - -/* These are the offset of the controller's registers */ -#define ATAPI_OFFSET_CONTROL 0x00 -#define ATAPI_OFFSET_STATUS 0x04 -#define ATAPI_OFFSET_DEV_ADDR 0x08 -#define ATAPI_OFFSET_DEV_TXBUF 0x0c -#define ATAPI_OFFSET_DEV_RXBUF 0x10 -#define ATAPI_OFFSET_INT_MASK 0x14 -#define ATAPI_OFFSET_INT_STATUS 0x18 -#define ATAPI_OFFSET_XFER_LEN 0x1c -#define ATAPI_OFFSET_LINE_STATUS 0x20 -#define ATAPI_OFFSET_SM_STATE 0x24 -#define ATAPI_OFFSET_TERMINATE 0x28 -#define ATAPI_OFFSET_PIO_TFRCNT 0x2c -#define ATAPI_OFFSET_DMA_TFRCNT 0x30 -#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34 -#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38 -#define ATAPI_OFFSET_REG_TIM_0 0x40 -#define ATAPI_OFFSET_PIO_TIM_0 0x44 -#define ATAPI_OFFSET_PIO_TIM_1 0x48 -#define ATAPI_OFFSET_MULTI_TIM_0 0x50 -#define ATAPI_OFFSET_MULTI_TIM_1 0x54 -#define ATAPI_OFFSET_MULTI_TIM_2 0x58 -#define ATAPI_OFFSET_ULTRA_TIM_0 0x60 -#define ATAPI_OFFSET_ULTRA_TIM_1 0x64 -#define ATAPI_OFFSET_ULTRA_TIM_2 0x68 -#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c - - -#define ATAPI_GET_CONTROL(base)\ - bfin_read16(base + ATAPI_OFFSET_CONTROL) -#define ATAPI_SET_CONTROL(base, val)\ - bfin_write16(base + ATAPI_OFFSET_CONTROL, val) -#define ATAPI_GET_STATUS(base)\ - bfin_read16(base + ATAPI_OFFSET_STATUS) -#define ATAPI_GET_DEV_ADDR(base)\ - bfin_read16(base + ATAPI_OFFSET_DEV_ADDR) -#define ATAPI_SET_DEV_ADDR(base, val)\ - bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val) -#define ATAPI_GET_DEV_TXBUF(base)\ - bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF) -#define ATAPI_SET_DEV_TXBUF(base, val)\ - bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val) -#define ATAPI_GET_DEV_RXBUF(base)\ - bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF) -#define ATAPI_SET_DEV_RXBUF(base, val)\ - bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val) -#define ATAPI_GET_INT_MASK(base)\ - bfin_read16(base + ATAPI_OFFSET_INT_MASK) -#define ATAPI_SET_INT_MASK(base, val)\ - bfin_write16(base + ATAPI_OFFSET_INT_MASK, val) -#define ATAPI_GET_INT_STATUS(base)\ - bfin_read16(base + ATAPI_OFFSET_INT_STATUS) -#define ATAPI_SET_INT_STATUS(base, val)\ - bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val) -#define ATAPI_GET_XFER_LEN(base)\ - bfin_read16(base + ATAPI_OFFSET_XFER_LEN) -#define ATAPI_SET_XFER_LEN(base, val)\ - bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val) -#define ATAPI_GET_LINE_STATUS(base)\ - bfin_read16(base + ATAPI_OFFSET_LINE_STATUS) -#define ATAPI_GET_SM_STATE(base)\ - bfin_read16(base + ATAPI_OFFSET_SM_STATE) -#define ATAPI_GET_TERMINATE(base)\ - bfin_read16(base + ATAPI_OFFSET_TERMINATE) -#define ATAPI_SET_TERMINATE(base, val)\ - bfin_write16(base + ATAPI_OFFSET_TERMINATE, val) -#define ATAPI_GET_PIO_TFRCNT(base)\ - bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT) -#define ATAPI_GET_DMA_TFRCNT(base)\ - bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT) -#define ATAPI_GET_UMAIN_TFRCNT(base)\ - bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT) -#define ATAPI_GET_UDMAOUT_TFRCNT(base)\ - bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT) -#define ATAPI_GET_REG_TIM_0(base)\ - bfin_read16(base + ATAPI_OFFSET_REG_TIM_0) -#define ATAPI_SET_REG_TIM_0(base, val)\ - bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val) -#define ATAPI_GET_PIO_TIM_0(base)\ - bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0) -#define ATAPI_SET_PIO_TIM_0(base, val)\ - bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val) -#define ATAPI_GET_PIO_TIM_1(base)\ - bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1) -#define ATAPI_SET_PIO_TIM_1(base, val)\ - bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val) -#define ATAPI_GET_MULTI_TIM_0(base)\ - bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0) -#define ATAPI_SET_MULTI_TIM_0(base, val)\ - bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val) -#define ATAPI_GET_MULTI_TIM_1(base)\ - bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1) -#define ATAPI_SET_MULTI_TIM_1(base, val)\ - bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val) -#define ATAPI_GET_MULTI_TIM_2(base)\ - bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2) -#define ATAPI_SET_MULTI_TIM_2(base, val)\ - bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val) -#define ATAPI_GET_ULTRA_TIM_0(base)\ - bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0) -#define ATAPI_SET_ULTRA_TIM_0(base, val)\ - bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val) -#define ATAPI_GET_ULTRA_TIM_1(base)\ - bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1) -#define ATAPI_SET_ULTRA_TIM_1(base, val)\ - bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val) -#define ATAPI_GET_ULTRA_TIM_2(base)\ - bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2) -#define ATAPI_SET_ULTRA_TIM_2(base, val)\ - bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val) -#define ATAPI_GET_ULTRA_TIM_3(base)\ - bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3) -#define ATAPI_SET_ULTRA_TIM_3(base, val)\ - bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val) - -#endif diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index 26a5e58221..ccf47a1da1 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -12,16 +12,39 @@ #include <dm/lists.h> #include <dt-bindings/clock/ast2500-scu.h> +/* + * MAC Clock Delay settings, taken from Aspeed SDK + */ +#define RGMII_TXCLK_ODLY 8 +#define RMII_RXCLK_IDLY 2 + +/* + * TGMII Clock Duty constants, taken from Aspeed SDK + */ +#define RGMII2_TXCK_DUTY 0x66 +#define RGMII1_TXCK_DUTY 0x64 + +#define D2PLL_DEFAULT_RATE (250 * 1000 * 1000) + DECLARE_GLOBAL_DATA_PTR; /* + * Clock divider/multiplier configuration struct. * For H-PLL and M-PLL the formula is * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1) * M - Numerator * N - Denumerator * P - Post Divider * They have the same layout in their control register. + * + * D-PLL and D2-PLL have extra divider (OD + 1), which is not + * yet needed and ignored by clock configurations. */ +struct ast2500_div_config { + unsigned int num; + unsigned int denum; + unsigned int post_div; +}; /* * Get the rate of the M-PLL clock from input clock frequency and @@ -29,11 +52,11 @@ DECLARE_GLOBAL_DATA_PTR; */ static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg) { - const ulong num = (mpll_reg >> SCU_MPLL_NUM_SHIFT) & SCU_MPLL_NUM_MASK; - const ulong denum = (mpll_reg >> SCU_MPLL_DENUM_SHIFT) - & SCU_MPLL_DENUM_MASK; - const ulong post_div = (mpll_reg >> SCU_MPLL_POST_SHIFT) - & SCU_MPLL_POST_MASK; + const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT; + const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK) + >> SCU_MPLL_DENUM_SHIFT; + const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK) + >> SCU_MPLL_POST_SHIFT; return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); } @@ -44,11 +67,11 @@ static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg) */ static ulong ast2500_get_hpll_rate(ulong clkin, u32 hpll_reg) { - const ulong num = (hpll_reg >> SCU_HPLL_NUM_SHIFT) & SCU_HPLL_NUM_MASK; - const ulong denum = (hpll_reg >> SCU_HPLL_DENUM_SHIFT) - & SCU_HPLL_DENUM_MASK; - const ulong post_div = (hpll_reg >> SCU_HPLL_POST_SHIFT) - & SCU_HPLL_POST_MASK; + const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT; + const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK) + >> SCU_HPLL_DENUM_SHIFT; + const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK) + >> SCU_HPLL_POST_SHIFT; return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); } @@ -110,6 +133,17 @@ static ulong ast2500_clk_get_rate(struct clk *clk) rate = ast2500_get_mpll_rate(clkin, readl(&priv->scu->m_pll_param)); break; + case BCLK_PCLK: + { + ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1) + & SCU_PCLK_DIV_MASK) + >> SCU_PCLK_DIV_SHIFT); + rate = ast2500_get_hpll_rate(clkin, + readl(&priv-> + scu->h_pll_param)); + rate = rate / apb_div; + } + break; case PCLK_UART1: rate = ast2500_get_uart_clk_rate(priv->scu, 1); break; @@ -132,44 +166,41 @@ static ulong ast2500_clk_get_rate(struct clk *clk) return rate; } -static void ast2500_scu_unlock(struct ast2500_scu *scu) -{ - writel(SCU_UNLOCK_VALUE, &scu->protection_key); - while (!readl(&scu->protection_key)) - ; -} - -static void ast2500_scu_lock(struct ast2500_scu *scu) -{ - writel(~SCU_UNLOCK_VALUE, &scu->protection_key); - while (readl(&scu->protection_key)) - ; -} - -static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate) +/* + * @input_rate - the rate of input clock in Hz + * @requested_rate - desired output rate in Hz + * @div - this is an IN/OUT parameter, at input all fields of the config + * need to be set to their maximum allowed values. + * The result (the best config we could find), would also be returned + * in this structure. + * + * @return The clock rate, when the resulting div_config is used. + */ +static ulong ast2500_calc_clock_config(ulong input_rate, ulong requested_rate, + struct ast2500_div_config *cfg) { - ulong clkin = ast2500_get_clkin(scu); - u32 mpll_reg; - /* - * There are not that many combinations of numerator, denumerator - * and post divider, so just brute force the best combination. - * However, to avoid overflow when multiplying, use kHz. + * The assumption is that kHz precision is good enough and + * also enough to avoid overflow when multiplying. */ - const ulong clkin_khz = clkin / 1000; - const ulong rate_khz = rate / 1000; - ulong best_num = 0; - ulong best_denum = 0; - ulong best_post = 0; - ulong delta = rate; - ulong num, denum, post; - - for (denum = 0; denum <= SCU_MPLL_DENUM_MASK; ++denum) { - for (post = 0; post <= SCU_MPLL_POST_MASK; ++post) { - num = (rate_khz * (post + 1) / clkin_khz) * (denum + 1); - ulong new_rate_khz = (clkin_khz - * ((num + 1) / (denum + 1))) - / (post + 1); + const ulong input_rate_khz = input_rate / 1000; + const ulong rate_khz = requested_rate / 1000; + const struct ast2500_div_config max_vals = *cfg; + struct ast2500_div_config it = { 0, 0, 0 }; + ulong delta = rate_khz; + ulong new_rate_khz = 0; + + for (; it.denum <= max_vals.denum; ++it.denum) { + for (it.post_div = 0; it.post_div <= max_vals.post_div; + ++it.post_div) { + it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) + * (it.denum + 1); + if (it.num > max_vals.num) + continue; + + new_rate_khz = (input_rate_khz + * ((it.num + 1) / (it.denum + 1))) + / (it.post_div + 1); /* Keep the rate below requested one. */ if (new_rate_khz > rate_khz) @@ -177,33 +208,172 @@ static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate) if (new_rate_khz - rate_khz < delta) { delta = new_rate_khz - rate_khz; - - best_num = num; - best_denum = denum; - best_post = post; - + *cfg = it; if (delta == 0) - goto rate_calc_done; + return new_rate_khz * 1000; } } } - rate_calc_done: + return new_rate_khz * 1000; +} + +static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate) +{ + ulong clkin = ast2500_get_clkin(scu); + u32 mpll_reg; + struct ast2500_div_config div_cfg = { + .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT), + .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT), + .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT), + }; + + ast2500_calc_clock_config(clkin, rate, &div_cfg); + mpll_reg = readl(&scu->m_pll_param); - mpll_reg &= ~((SCU_MPLL_POST_MASK << SCU_MPLL_POST_SHIFT) - | (SCU_MPLL_NUM_MASK << SCU_MPLL_NUM_SHIFT) - | (SCU_MPLL_DENUM_MASK << SCU_MPLL_DENUM_SHIFT)); - mpll_reg |= (best_post << SCU_MPLL_POST_SHIFT) - | (best_num << SCU_MPLL_NUM_SHIFT) - | (best_denum << SCU_MPLL_DENUM_SHIFT); - - ast2500_scu_unlock(scu); + mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK + | SCU_MPLL_DENUM_MASK); + mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT) + | (div_cfg.num << SCU_MPLL_NUM_SHIFT) + | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT); + + ast_scu_unlock(scu); writel(mpll_reg, &scu->m_pll_param); - ast2500_scu_lock(scu); + ast_scu_lock(scu); return ast2500_get_mpll_rate(clkin, mpll_reg); } +static ulong ast2500_configure_mac(struct ast2500_scu *scu, int index) +{ + ulong clkin = ast2500_get_clkin(scu); + ulong hpll_rate = ast2500_get_hpll_rate(clkin, + readl(&scu->h_pll_param)); + ulong required_rate; + u32 hwstrap; + u32 divisor; + u32 reset_bit; + u32 clkstop_bit; + + /* + * According to data sheet, for 10/100 mode the MAC clock frequency + * should be at least 25MHz and for 1000 mode at least 100MHz + */ + hwstrap = readl(&scu->hwstrap); + if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII)) + required_rate = 100 * 1000 * 1000; + else + required_rate = 25 * 1000 * 1000; + + divisor = hpll_rate / required_rate; + + if (divisor < 4) { + /* Clock can't run fast enough, but let's try anyway */ + debug("MAC clock too slow\n"); + divisor = 4; + } else if (divisor > 16) { + /* Can't slow down the clock enough, but let's try anyway */ + debug("MAC clock too fast\n"); + divisor = 16; + } + + switch (index) { + case 1: + reset_bit = SCU_SYSRESET_MAC1; + clkstop_bit = SCU_CLKSTOP_MAC1; + break; + case 2: + reset_bit = SCU_SYSRESET_MAC2; + clkstop_bit = SCU_CLKSTOP_MAC2; + break; + default: + return -EINVAL; + } + + ast_scu_unlock(scu); + clrsetbits_le32(&scu->clk_sel1, SCU_MACCLK_MASK, + ((divisor - 2) / 2) << SCU_MACCLK_SHIFT); + + /* + * Disable MAC, start its clock and re-enable it. + * The procedure and the delays (100us & 10ms) are + * specified in the datasheet. + */ + setbits_le32(&scu->sysreset_ctrl1, reset_bit); + udelay(100); + clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit); + mdelay(10); + clrbits_le32(&scu->sysreset_ctrl1, reset_bit); + + writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT) + | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT), + &scu->clk_duty_sel); + + ast_scu_lock(scu); + + return required_rate; +} + +static ulong ast2500_configure_d2pll(struct ast2500_scu *scu, ulong rate) +{ + /* + * The values and the meaning of the next three + * parameters are undocumented. Taken from Aspeed SDK. + */ + const u32 d2_pll_ext_param = 0x2c; + const u32 d2_pll_sip = 0x11; + const u32 d2_pll_sic = 0x18; + u32 clk_delay_settings = + (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT) + | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT) + | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT) + | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT); + struct ast2500_div_config div_cfg = { + .num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT, + .denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT, + .post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT, + }; + ulong clkin = ast2500_get_clkin(scu); + ulong new_rate; + + ast_scu_unlock(scu); + writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT) + | SCU_D2PLL_EXT1_OFF + | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]); + + /* + * Select USB2.0 port1 PHY clock as a clock source for GCRT. + * This would disconnect it from D2-PLL. + */ + clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF, + SCU_MISC_GCRT_USB20CLK); + + new_rate = ast2500_calc_clock_config(clkin, rate, &div_cfg); + writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT) + | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT) + | (div_cfg.num << SCU_D2PLL_NUM_SHIFT) + | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT) + | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT), + &scu->d2_pll_param); + + clrbits_le32(&scu->d2_pll_ext_param[0], + SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET); + + clrsetbits_le32(&scu->misc_ctrl2, + SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL + | SCU_MISC2_RGMII_CLKDIV_MASK | + SCU_MISC2_RMII_CLKDIV_MASK, + (4 << SCU_MISC2_RMII_CLKDIV_SHIFT)); + + writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay); + writel(clk_delay_settings, &scu->mac_clk_delay_100M); + writel(clk_delay_settings, &scu->mac_clk_delay_10M); + + ast_scu_lock(scu); + + return new_rate; +} + static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate) { struct ast2500_clk_priv *priv = dev_get_priv(clk->dev); @@ -214,6 +384,9 @@ static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate) case MCLK_DDR: new_rate = ast2500_configure_ddr(priv->scu, rate); break; + case PLL_D2PLL: + new_rate = ast2500_configure_d2pll(priv->scu, rate); + break; default: return -ENOENT; } @@ -221,9 +394,35 @@ static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate) return new_rate; } +static int ast2500_clk_enable(struct clk *clk) +{ + struct ast2500_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + /* + * For MAC clocks the clock rate is + * configured based on whether RGMII or RMII mode has been selected + * through hardware strapping. + */ + case PCLK_MAC1: + ast2500_configure_mac(priv->scu, 1); + break; + case PCLK_MAC2: + ast2500_configure_mac(priv->scu, 2); + break; + case PLL_D2PLL: + ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE); + default: + return -ENOENT; + } + + return 0; +} + struct clk_ops ast2500_clk_ops = { .get_rate = ast2500_clk_get_rate, .set_rate = ast2500_clk_set_rate, + .enable = ast2500_clk_enable, }; static int ast2500_clk_probe(struct udevice *dev) diff --git a/drivers/clk/clk_stm32f7.c b/drivers/clk/clk_stm32f7.c index 0d86395d47..da3c204ff5 100644 --- a/drivers/clk/clk_stm32f7.c +++ b/drivers/clk/clk_stm32f7.c @@ -228,56 +228,17 @@ static int stm32_clk_enable(struct clk *clk) void clock_setup(int peripheral) { switch (peripheral) { - case GPIO_A_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_A_EN); - break; - case GPIO_B_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_B_EN); - break; - case GPIO_C_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_C_EN); - break; - case GPIO_D_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_D_EN); - break; - case GPIO_E_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_E_EN); - break; - case GPIO_F_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_F_EN); - break; - case GPIO_G_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_G_EN); - break; - case GPIO_H_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_H_EN); - break; - case GPIO_I_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_I_EN); - break; - case GPIO_J_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_J_EN); - break; - case GPIO_K_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_GPIO_K_EN); - break; case SYSCFG_CLOCK_CFG: setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_SYSCFGEN); break; case TIMER2_CLOCK_CFG: setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_TIM2EN); break; - case FMC_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb3enr, RCC_AHB3ENR_FMC_EN); - break; case STMMAC_CLOCK_CFG: setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_EN); setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_RX_EN); setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_TX_EN); break; - case QSPI_CLOCK_CFG: - setbits_le32(&STM32_RCC->ahb3enr, RCC_AHB3ENR_QSPI_EN); - break; default: break; } diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c index 6125bbb558..375ff9d0e3 100644 --- a/drivers/crypto/fsl/jobdesc.c +++ b/drivers/crypto/fsl/jobdesc.c @@ -204,7 +204,7 @@ void inline_cnstr_jobdesc_hash(uint32_t *desc, append_store(desc, dma_addr_out, storelen, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); } - +#ifndef CONFIG_SPL_BUILD void inline_cnstr_jobdesc_blob_encap(uint32_t *desc, uint8_t *key_idnfr, uint8_t *plain_txt, uint8_t *enc_blob, uint32_t in_sz) @@ -252,7 +252,7 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr, append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB); } - +#endif /* * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 1b882291e4..986eabfb08 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -47,8 +47,7 @@ static inline void start_jr0(uint8_t sec_idx) * VIRT_EN_INCL = 1 & VIRT_EN_POR = 0 & SEC_SCFGR_VIRT_EN = 1 */ if ((ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) || - (!(ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) && - (scfgr & SEC_SCFGR_VIRT_EN))) + (scfgr & SEC_SCFGR_VIRT_EN)) sec_out32(&sec->jrstartr, CONFIG_JRSTARTR_JR0); } else { /* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */ @@ -342,7 +341,9 @@ static void desc_done(uint32_t status, void *arg) { struct result *x = arg; x->status = status; +#ifndef CONFIG_SPL_BUILD caam_jr_strstatus(status); +#endif x->done = 1; } @@ -436,7 +437,11 @@ static inline int sec_reset_idx(uint8_t sec_idx) return 0; } - +int sec_reset(void) +{ + return sec_reset_idx(0); +} +#ifndef CONFIG_SPL_BUILD static int instantiate_rng(uint8_t sec_idx) { struct result op; @@ -472,11 +477,6 @@ static int instantiate_rng(uint8_t sec_idx) return ret; } -int sec_reset(void) -{ - return sec_reset_idx(0); -} - static u8 get_rng_vid(uint8_t sec_idx) { ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); @@ -561,7 +561,7 @@ static int rng_init(uint8_t sec_idx) return ret; } - +#endif int sec_init_idx(uint8_t sec_idx) { ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); @@ -586,7 +586,7 @@ int sec_init_idx(uint8_t sec_idx) * For AXI Read - Cacheable, Read allocate * Only For LS2080a, to solve CAAM coherency issues */ -#ifdef CONFIG_LS2080A +#ifdef CONFIG_ARCH_LS2080A mcr = (mcr & ~MCFGR_AWCACHE_MASK) | (0xb << MCFGR_AWCACHE_SHIFT); mcr = (mcr & ~MCFGR_ARCACHE_MASK) | (0x6 << MCFGR_ARCACHE_SHIFT); #else @@ -634,7 +634,7 @@ int sec_init_idx(uint8_t sec_idx) pamu_enable(); #endif - +#ifndef CONFIG_SPL_BUILD if (get_rng_vid(sec_idx) >= 4) { if (rng_init(sec_idx) < 0) { printf("SEC%u: RNG instantiation failed\n", sec_idx); @@ -642,7 +642,7 @@ int sec_init_idx(uint8_t sec_idx) } printf("SEC%u: RNG instantiated\n", sec_idx); } - +#endif return ret; } diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c index d6a8fcb216..b45a8797e4 100644 --- a/drivers/ddr/fsl/options.c +++ b/drivers/ddr/fsl/options.c @@ -33,7 +33,7 @@ struct dynamic_odt { /* Quad rank is not verified yet due availability. * Replacing 20 OHM with 34 OHM since DDR4 doesn't have 20 OHM option */ -static const struct dynamic_odt single_Q[4] = { +static __maybe_unused const struct dynamic_odt single_Q[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS_AND_OTHER_DIMM, @@ -60,7 +60,7 @@ static const struct dynamic_odt single_Q[4] = { } }; -static const struct dynamic_odt single_D[4] = { +static __maybe_unused const struct dynamic_odt single_D[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -77,7 +77,7 @@ static const struct dynamic_odt single_D[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt single_S[4] = { +static __maybe_unused const struct dynamic_odt single_S[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -89,7 +89,7 @@ static const struct dynamic_odt single_S[4] = { {0, 0, 0, 0}, }; -static const struct dynamic_odt dual_DD[4] = { +static __maybe_unused const struct dynamic_odt dual_DD[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_SAME_DIMM, @@ -116,7 +116,7 @@ static const struct dynamic_odt dual_DD[4] = { } }; -static const struct dynamic_odt dual_DS[4] = { +static __maybe_unused const struct dynamic_odt dual_DS[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_SAME_DIMM, @@ -137,7 +137,7 @@ static const struct dynamic_odt dual_DS[4] = { }, {0, 0, 0, 0} }; -static const struct dynamic_odt dual_SD[4] = { +static __maybe_unused const struct dynamic_odt dual_SD[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_ALL, @@ -159,7 +159,7 @@ static const struct dynamic_odt dual_SD[4] = { } }; -static const struct dynamic_odt dual_SS[4] = { +static __maybe_unused const struct dynamic_odt dual_SS[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_ALL, @@ -176,7 +176,7 @@ static const struct dynamic_odt dual_SS[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_D0[4] = { +static __maybe_unused const struct dynamic_odt dual_D0[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_SAME_DIMM, @@ -193,7 +193,7 @@ static const struct dynamic_odt dual_D0[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_0D[4] = { +static __maybe_unused const struct dynamic_odt dual_0D[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, { /* cs2 */ @@ -210,7 +210,7 @@ static const struct dynamic_odt dual_0D[4] = { } }; -static const struct dynamic_odt dual_S0[4] = { +static __maybe_unused const struct dynamic_odt dual_S0[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS, @@ -223,7 +223,7 @@ static const struct dynamic_odt dual_S0[4] = { }; -static const struct dynamic_odt dual_0S[4] = { +static __maybe_unused const struct dynamic_odt dual_0S[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, { /* cs2 */ @@ -236,7 +236,7 @@ static const struct dynamic_odt dual_0S[4] = { }; -static const struct dynamic_odt odt_unknown[4] = { +static __maybe_unused const struct dynamic_odt odt_unknown[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS, @@ -263,7 +263,7 @@ static const struct dynamic_odt odt_unknown[4] = { } }; #elif defined(CONFIG_SYS_FSL_DDR3) -static const struct dynamic_odt single_Q[4] = { +static __maybe_unused const struct dynamic_odt single_Q[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS_AND_OTHER_DIMM, @@ -290,7 +290,7 @@ static const struct dynamic_odt single_Q[4] = { } }; -static const struct dynamic_odt single_D[4] = { +static __maybe_unused const struct dynamic_odt single_D[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -307,7 +307,7 @@ static const struct dynamic_odt single_D[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt single_S[4] = { +static __maybe_unused const struct dynamic_odt single_S[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -319,7 +319,7 @@ static const struct dynamic_odt single_S[4] = { {0, 0, 0, 0}, }; -static const struct dynamic_odt dual_DD[4] = { +static __maybe_unused const struct dynamic_odt dual_DD[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_SAME_DIMM, @@ -346,7 +346,7 @@ static const struct dynamic_odt dual_DD[4] = { } }; -static const struct dynamic_odt dual_DS[4] = { +static __maybe_unused const struct dynamic_odt dual_DS[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_SAME_DIMM, @@ -367,7 +367,7 @@ static const struct dynamic_odt dual_DS[4] = { }, {0, 0, 0, 0} }; -static const struct dynamic_odt dual_SD[4] = { +static __maybe_unused const struct dynamic_odt dual_SD[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_ALL, @@ -389,7 +389,7 @@ static const struct dynamic_odt dual_SD[4] = { } }; -static const struct dynamic_odt dual_SS[4] = { +static __maybe_unused const struct dynamic_odt dual_SS[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_ALL, @@ -406,7 +406,7 @@ static const struct dynamic_odt dual_SS[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_D0[4] = { +static __maybe_unused const struct dynamic_odt dual_D0[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_SAME_DIMM, @@ -423,7 +423,7 @@ static const struct dynamic_odt dual_D0[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_0D[4] = { +static __maybe_unused const struct dynamic_odt dual_0D[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, { /* cs2 */ @@ -440,7 +440,7 @@ static const struct dynamic_odt dual_0D[4] = { } }; -static const struct dynamic_odt dual_S0[4] = { +static __maybe_unused const struct dynamic_odt dual_S0[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS, @@ -453,7 +453,7 @@ static const struct dynamic_odt dual_S0[4] = { }; -static const struct dynamic_odt dual_0S[4] = { +static __maybe_unused const struct dynamic_odt dual_0S[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, { /* cs2 */ @@ -466,7 +466,7 @@ static const struct dynamic_odt dual_0S[4] = { }; -static const struct dynamic_odt odt_unknown[4] = { +static __maybe_unused const struct dynamic_odt odt_unknown[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS, @@ -493,14 +493,14 @@ static const struct dynamic_odt odt_unknown[4] = { } }; #else /* CONFIG_SYS_FSL_DDR3 */ -static const struct dynamic_odt single_Q[4] = { +static __maybe_unused const struct dynamic_odt single_Q[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} }; -static const struct dynamic_odt single_D[4] = { +static __maybe_unused const struct dynamic_odt single_D[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -517,7 +517,7 @@ static const struct dynamic_odt single_D[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt single_S[4] = { +static __maybe_unused const struct dynamic_odt single_S[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -529,7 +529,7 @@ static const struct dynamic_odt single_S[4] = { {0, 0, 0, 0}, }; -static const struct dynamic_odt dual_DD[4] = { +static __maybe_unused const struct dynamic_odt dual_DD[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_OTHER_DIMM, @@ -556,7 +556,7 @@ static const struct dynamic_odt dual_DD[4] = { } }; -static const struct dynamic_odt dual_DS[4] = { +static __maybe_unused const struct dynamic_odt dual_DS[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_OTHER_DIMM, @@ -578,7 +578,7 @@ static const struct dynamic_odt dual_DS[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_SD[4] = { +static __maybe_unused const struct dynamic_odt dual_SD[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_OTHER_DIMM, @@ -600,7 +600,7 @@ static const struct dynamic_odt dual_SD[4] = { } }; -static const struct dynamic_odt dual_SS[4] = { +static __maybe_unused const struct dynamic_odt dual_SS[4] = { { /* cs0 */ FSL_DDR_ODT_OTHER_DIMM, FSL_DDR_ODT_OTHER_DIMM, @@ -617,7 +617,7 @@ static const struct dynamic_odt dual_SS[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_D0[4] = { +static __maybe_unused const struct dynamic_odt dual_D0[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_ALL, @@ -634,7 +634,7 @@ static const struct dynamic_odt dual_D0[4] = { {0, 0, 0, 0} }; -static const struct dynamic_odt dual_0D[4] = { +static __maybe_unused const struct dynamic_odt dual_0D[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, { /* cs2 */ @@ -651,7 +651,7 @@ static const struct dynamic_odt dual_0D[4] = { } }; -static const struct dynamic_odt dual_S0[4] = { +static __maybe_unused const struct dynamic_odt dual_S0[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS, @@ -664,7 +664,7 @@ static const struct dynamic_odt dual_S0[4] = { }; -static const struct dynamic_odt dual_0S[4] = { +static __maybe_unused const struct dynamic_odt dual_0S[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, { /* cs2 */ @@ -677,7 +677,7 @@ static const struct dynamic_odt dual_0S[4] = { }; -static const struct dynamic_odt odt_unknown[4] = { +static __maybe_unused const struct dynamic_odt odt_unknown[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, FSL_DDR_ODT_CS, @@ -916,7 +916,7 @@ unsigned int populate_memctl_options(const common_timing_params_t *common_dimm, if ((pdimm[0].data_width >= 64) && \ (pdimm[0].data_width <= 72)) popts->data_bus_width = 0; - else if ((pdimm[0].data_width >= 32) || \ + else if ((pdimm[0].data_width >= 32) && \ (pdimm[0].data_width <= 40)) popts->data_bus_width = 1; else { diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig new file mode 100644 index 0000000000..4c32426e0e --- /dev/null +++ b/drivers/firmware/Kconfig @@ -0,0 +1,6 @@ +config FIRMWARE + bool + +config ARM_PSCI_FW + bool + select FIRMWARE diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile new file mode 100644 index 0000000000..b208255368 --- /dev/null +++ b/drivers/firmware/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_FIRMWARE) += firmware-uclass.o +obj-$(CONFIG_ARM_PSCI_FW) += psci.o diff --git a/drivers/firmware/firmware-uclass.c b/drivers/firmware/firmware-uclass.c new file mode 100644 index 0000000000..01b6a44b9d --- /dev/null +++ b/drivers/firmware/firmware-uclass.c @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/uclass.h> + +/* Firmware access is platform-dependent. No generic code in uclass */ +UCLASS_DRIVER(firmware) = { + .id = UCLASS_FIRMWARE, + .name = "firmware", +}; diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c new file mode 100644 index 0000000000..40fba6432c --- /dev/null +++ b/drivers/firmware/psci.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * Based on drivers/firmware/psci.c from Linux: + * Copyright (C) 2015 ARM Limited + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm/device.h> +#include <dm/lists.h> +#include <libfdt.h> +#include <linux/arm-smccc.h> +#include <linux/errno.h> +#include <linux/psci.h> + +psci_fn *invoke_psci_fn; + +static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res.a0; +} + +static unsigned long __invoke_psci_fn_smc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res.a0; +} + +static int psci_bind(struct udevice *dev) +{ + /* No SYSTEM_RESET support for PSCI 0.1 */ + if (of_device_is_compatible(dev, "arm,psci-0.2") || + of_device_is_compatible(dev, "arm,psci-1.0")) { + int ret; + + /* bind psci-sysreset optionally */ + ret = device_bind_driver(dev, "psci-sysreset", "psci-sysreset", + NULL); + if (ret) + debug("PSCI System Reset was not bound.\n"); + } + + return 0; +} + +static int psci_probe(struct udevice *dev) +{ + DECLARE_GLOBAL_DATA_PTR; + const char *method; + + method = fdt_stringlist_get(gd->fdt_blob, dev->of_offset, "method", 0, + NULL); + if (!method) { + printf("missing \"method\" property\n"); + return -ENXIO; + } + + if (!strcmp("hvc", method)) { + invoke_psci_fn = __invoke_psci_fn_hvc; + } else if (!strcmp("smc", method)) { + invoke_psci_fn = __invoke_psci_fn_smc; + } else { + printf("invalid \"method\" property: %s\n", method); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id psci_of_match[] = { + { .compatible = "arm,psci" }, + { .compatible = "arm,psci-0.2" }, + { .compatible = "arm,psci-1.0" }, + {}, +}; + +U_BOOT_DRIVER(psci) = { + .name = "psci", + .id = UCLASS_FIRMWARE, + .of_match = psci_of_match, + .bind = psci_bind, + .probe = psci_probe, +}; diff --git a/drivers/fpga/ivm_core.c b/drivers/fpga/ivm_core.c index 03aea625d5..78e9cc46ac 100644 --- a/drivers/fpga/ivm_core.c +++ b/drivers/fpga/ivm_core.c @@ -3142,7 +3142,7 @@ signed char ispVMProcessLVDS(unsigned short a_usLVDSCount) } #ifdef DEBUG - printf(");\n", a_usLVDSCount); + printf(");\n"); #endif /* DEBUG */ return 0; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c95e9acd5f..99516119ff 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -171,6 +171,15 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. +config STM32F7_GPIO + bool "ST STM32 GPIO driver" + depends on DM_GPIO && STM32 + default y + help + Device model driver support for STM32 GPIO controller. It should be + usable on many stm32 families like stm32f4 & stm32H7. + Tested on STM32F7. + config MVEBU_GPIO bool "Marvell MVEBU GPIO driver" depends on DM_GPIO && ARCH_MVEBU diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 27f8068e3e..0ca845f54c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -49,6 +49,7 @@ oby-$(CONFIG_SX151X) += sx151x.o obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o +obj-$(CONFIG_STM32F7_GPIO) += stm32f7_gpio.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c new file mode 100644 index 0000000000..5e0546357f --- /dev/null +++ b/drivers/gpio/stm32f7_gpio.c @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2017 + * Vikas Manocha, <vikas.manocha@st.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> +#include <asm/arch/gpio.h> +#include <asm/arch/stm32.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <linux/errno.h> +#include <linux/io.h> + +#define MAX_SIZE_BANK_NAME 5 +#define STM32_GPIOS_PER_BANK 16 +#define MODE_BITS(gpio_pin) (gpio_pin * 2) +#define MODE_BITS_MASK 3 +#define IN_OUT_BIT_INDEX(gpio_pin) (1UL << (gpio_pin)) + +DECLARE_GLOBAL_DATA_PTR; + +static int stm32_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index = MODE_BITS(offset); + int mask = MODE_BITS_MASK << bits_index; + + clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_IN << bits_index); + + return 0; +} + +static int stm32_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int bits_index = MODE_BITS(offset); + int mask = MODE_BITS_MASK << bits_index; + + clrsetbits_le32(®s->moder, mask, STM32_GPIO_MODE_OUT << bits_index); + mask = IN_OUT_BIT_INDEX(offset); + clrsetbits_le32(®s->odr, mask, value ? mask : 0); + + return 0; +} + +static int stm32_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + + return readl(®s->idr) & IN_OUT_BIT_INDEX(offset) ? 1 : 0; +} + +static int stm32_gpio_set_value(struct udevice *dev, unsigned offset, int value) +{ + struct stm32_gpio_priv *priv = dev_get_priv(dev); + struct stm32_gpio_regs *regs = priv->regs; + int mask = IN_OUT_BIT_INDEX(offset); + + clrsetbits_le32(®s->odr, mask, value ? mask : 0); + + return 0; +} + +static const struct dm_gpio_ops gpio_stm32_ops = { + .direction_input = stm32_gpio_direction_input, + .direction_output = stm32_gpio_direction_output, + .get_value = stm32_gpio_get_value, + .set_value = stm32_gpio_set_value, +}; + +static int gpio_stm32_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct stm32_gpio_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + char *name; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = (struct stm32_gpio_regs *)addr; + name = (char *)fdtdec_locate_byte_array(gd->fdt_blob, + dev_of_offset(dev), + "st,bank-name", + MAX_SIZE_BANK_NAME); + if (!name) + return -EINVAL; + uc_priv->bank_name = name; + uc_priv->gpio_count = STM32_GPIOS_PER_BANK; + debug("%s, addr = 0x%p, bank_name = %s\n", __func__, (u32 *)priv->regs, + uc_priv->bank_name); + +#ifdef CONFIG_CLK + struct clk clk; + int ret; + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + debug("clock enabled for device %s\n", dev->name); +#endif + + return 0; +} + +static const struct udevice_id stm32_gpio_ids[] = { + { .compatible = "st,stm32-gpio" }, + { } +}; + +U_BOOT_DRIVER(gpio_stm32) = { + .name = "gpio_stm32", + .id = UCLASS_GPIO, + .of_match = stm32_gpio_ids, + .probe = gpio_stm32_probe, + .ops = &gpio_stm32_ops, + .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS, + .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv), +}; diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 8d2bb18504..3f40e83830 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -352,6 +352,7 @@ static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun8i-a33-pinctrl", a_all), ID("allwinner,sun8i-a83t-pinctrl", a_all), ID("allwinner,sun8i-h3-pinctrl", a_all), + ID("allwinner,sun8i-r40-pinctrl", a_all), ID("allwinner,sun9i-a80-pinctrl", a_all), ID("allwinner,sun6i-a31-r-pinctrl", l_2), ID("allwinner,sun8i-a23-r-pinctrl", l_1), diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 4e9afc120a..c58bc1e1cf 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -114,6 +114,15 @@ config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED enable status register. This config option can be enabled in such cases. +config SYS_I2C_ASPEED + bool "Aspeed I2C Controller" + depends on DM_I2C && ARCH_ASPEED + help + Say yes here to select Aspeed I2C Host Controller. The driver + supports AST2500 and AST2400 controllers, but is very limited. + Only single master mode is supported and only byte-by-byte + synchronous reads and writes are supported, no Pool Buffers or DMA. + config SYS_I2C_INTEL bool "Intel I2C/SMBUS driver" depends on DM_I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 4872c1d702..d20fe7bb4a 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_I2C_MV) += mv_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o +obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o diff --git a/drivers/i2c/ast_i2c.c b/drivers/i2c/ast_i2c.c new file mode 100644 index 0000000000..16dfb57066 --- /dev/null +++ b/drivers/i2c/ast_i2c.c @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2012-2020 ASPEED Technology Inc. + * Copyright 2016 IBM Corporation + * Copyright 2017 Google, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/scu_ast2500.h> + +#include "ast_i2c.h" + +#define I2C_TIMEOUT_US 100000 +#define I2C_SLEEP_STEP_US 20 + +#define HIGHSPEED_TTIMEOUT 3 + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Device private data + */ +struct ast_i2c_priv { + /* This device's clock */ + struct clk clk; + /* Device registers */ + struct ast_i2c_regs *regs; + /* I2C speed in Hz */ + int speed; +}; + +/* + * Given desired divider ratio, return the value that needs to be set + * in Clock and AC Timing Control register + */ +static u32 get_clk_reg_val(ulong divider_ratio) +{ + ulong inc = 0, div; + ulong scl_low, scl_high, data; + + for (div = 0; divider_ratio >= 16; div++) { + inc |= (divider_ratio & 1); + divider_ratio >>= 1; + } + divider_ratio += inc; + scl_low = (divider_ratio >> 1) - 1; + scl_high = divider_ratio - scl_low - 2; + data = I2CD_CACTC_BASE + | (scl_high << I2CD_TCKHIGH_SHIFT) + | (scl_low << I2CD_TCKLOW_SHIFT) + | (div << I2CD_BASE_DIV_SHIFT); + + return data; +} + +static void ast_i2c_clear_interrupts(struct udevice *dev) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + + writel(~0, &priv->regs->isr); +} + +static void ast_i2c_init_bus(struct udevice *dev) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + + /* Reset device */ + writel(0, &priv->regs->fcr); + /* Enable Master Mode. Assuming single-master */ + writel(I2CD_MASTER_EN + | I2CD_M_SDA_LOCK_EN + | I2CD_MULTI_MASTER_DIS | I2CD_M_SCL_DRIVE_EN, + &priv->regs->fcr); + /* Enable Interrupts */ + writel(I2CD_INTR_TX_ACK + | I2CD_INTR_TX_NAK + | I2CD_INTR_RX_DONE + | I2CD_INTR_BUS_RECOVER_DONE + | I2CD_INTR_NORMAL_STOP + | I2CD_INTR_ABNORMAL, &priv->regs->icr); +} + +static int ast_i2c_ofdata_to_platdata(struct udevice *dev) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + int ret; + + priv->regs = dev_get_addr_ptr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) { + debug("%s: Can't get clock for %s: %d\n", __func__, dev->name, + ret); + return ret; + } + + return 0; +} + +static int ast_i2c_probe(struct udevice *dev) +{ + struct ast2500_scu *scu; + + debug("Enabling I2C%u\n", dev->seq); + + /* + * Get all I2C devices out of Reset. + * Only needs to be done once, but doing it for every + * device does not hurt. + */ + scu = ast_get_scu(); + ast_scu_unlock(scu); + clrbits_le32(&scu->sysreset_ctrl1, SCU_SYSRESET_I2C); + ast_scu_lock(scu); + + ast_i2c_init_bus(dev); + + return 0; +} + +static int ast_i2c_wait_isr(struct udevice *dev, u32 flag) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + int timeout = I2C_TIMEOUT_US; + + while (!(readl(&priv->regs->isr) & flag) && timeout > 0) { + udelay(I2C_SLEEP_STEP_US); + timeout -= I2C_SLEEP_STEP_US; + } + + ast_i2c_clear_interrupts(dev); + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int ast_i2c_send_stop(struct udevice *dev) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + + writel(I2CD_M_STOP_CMD, &priv->regs->csr); + + return ast_i2c_wait_isr(dev, I2CD_INTR_NORMAL_STOP); +} + +static int ast_i2c_wait_tx(struct udevice *dev) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + int timeout = I2C_TIMEOUT_US; + u32 flag = I2CD_INTR_TX_ACK | I2CD_INTR_TX_NAK; + u32 status = readl(&priv->regs->isr) & flag; + int ret = 0; + + while (!status && timeout > 0) { + status = readl(&priv->regs->isr) & flag; + udelay(I2C_SLEEP_STEP_US); + timeout -= I2C_SLEEP_STEP_US; + } + + if (status == I2CD_INTR_TX_NAK) + ret = -EREMOTEIO; + + if (timeout <= 0) + ret = -ETIMEDOUT; + + ast_i2c_clear_interrupts(dev); + + return ret; +} + +static int ast_i2c_start_txn(struct udevice *dev, uint devaddr) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + + /* Start and Send Device Address */ + writel(devaddr, &priv->regs->trbbr); + writel(I2CD_M_START_CMD | I2CD_M_TX_CMD, &priv->regs->csr); + + return ast_i2c_wait_tx(dev); +} + +static int ast_i2c_read_data(struct udevice *dev, u8 chip_addr, u8 *buffer, + size_t len, bool send_stop) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + u32 i2c_cmd = I2CD_M_RX_CMD; + int ret; + + ret = ast_i2c_start_txn(dev, (chip_addr << 1) | I2C_M_RD); + if (ret < 0) + return ret; + + for (; len > 0; len--, buffer++) { + if (len == 1) + i2c_cmd |= I2CD_M_S_RX_CMD_LAST; + writel(i2c_cmd, &priv->regs->csr); + ret = ast_i2c_wait_isr(dev, I2CD_INTR_RX_DONE); + if (ret < 0) + return ret; + *buffer = (readl(&priv->regs->trbbr) & I2CD_RX_DATA_MASK) + >> I2CD_RX_DATA_SHIFT; + } + ast_i2c_clear_interrupts(dev); + + if (send_stop) + return ast_i2c_send_stop(dev); + + return 0; +} + +static int ast_i2c_write_data(struct udevice *dev, u8 chip_addr, u8 + *buffer, size_t len, bool send_stop) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + int ret; + + ret = ast_i2c_start_txn(dev, (chip_addr << 1)); + if (ret < 0) + return ret; + + for (; len > 0; len--, buffer++) { + writel(*buffer, &priv->regs->trbbr); + writel(I2CD_M_TX_CMD, &priv->regs->csr); + ret = ast_i2c_wait_tx(dev); + if (ret < 0) + return ret; + } + + if (send_stop) + return ast_i2c_send_stop(dev); + + return 0; +} + +static int ast_i2c_deblock(struct udevice *dev) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + struct ast_i2c_regs *regs = priv->regs; + u32 csr = readl(®s->csr); + bool sda_high = csr & I2CD_SDA_LINE_STS; + bool scl_high = csr & I2CD_SCL_LINE_STS; + int ret = 0; + + if (sda_high && scl_high) { + /* Bus is idle, no deblocking needed. */ + return 0; + } else if (sda_high) { + /* Send stop command */ + debug("Unterminated TXN in (%x), sending stop\n", csr); + ret = ast_i2c_send_stop(dev); + } else if (scl_high) { + /* Possibly stuck slave */ + debug("Bus stuck (%x), attempting recovery\n", csr); + writel(I2CD_BUS_RECOVER_CMD, ®s->csr); + ret = ast_i2c_wait_isr(dev, I2CD_INTR_BUS_RECOVER_DONE); + } else { + /* Just try to reinit the device. */ + ast_i2c_init_bus(dev); + } + + return ret; +} + +static int ast_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) +{ + int ret; + + ret = ast_i2c_deblock(dev); + if (ret < 0) + return ret; + + debug("i2c_xfer: %d messages\n", nmsgs); + for (; nmsgs > 0; nmsgs--, msg++) { + if (msg->flags & I2C_M_RD) { + debug("i2c_read: chip=0x%x, len=0x%x, flags=0x%x\n", + msg->addr, msg->len, msg->flags); + ret = ast_i2c_read_data(dev, msg->addr, msg->buf, + msg->len, (nmsgs == 1)); + } else { + debug("i2c_write: chip=0x%x, len=0x%x, flags=0x%x\n", + msg->addr, msg->len, msg->flags); + ret = ast_i2c_write_data(dev, msg->addr, msg->buf, + msg->len, (nmsgs == 1)); + } + if (ret) { + debug("%s: error (%d)\n", __func__, ret); + return -EREMOTEIO; + } + } + + return 0; +} + +static int ast_i2c_set_speed(struct udevice *dev, unsigned int speed) +{ + struct ast_i2c_priv *priv = dev_get_priv(dev); + struct ast_i2c_regs *regs = priv->regs; + ulong i2c_rate, divider; + + debug("Setting speed for I2C%d to <%u>\n", dev->seq, speed); + if (!speed) { + debug("No valid speed specified\n"); + return -EINVAL; + } + + i2c_rate = clk_get_rate(&priv->clk); + divider = i2c_rate / speed; + + priv->speed = speed; + if (speed > I2C_HIGHSPEED_RATE) { + debug("Enable High Speed\n"); + setbits_le32(®s->fcr, I2CD_M_HIGH_SPEED_EN + | I2CD_M_SDA_DRIVE_1T_EN + | I2CD_SDA_DRIVE_1T_EN); + writel(HIGHSPEED_TTIMEOUT, ®s->cactcr2); + } else { + debug("Enabling Normal Speed\n"); + writel(I2CD_NO_TIMEOUT_CTRL, ®s->cactcr2); + } + + writel(get_clk_reg_val(divider), ®s->cactcr1); + ast_i2c_clear_interrupts(dev); + + return 0; +} + +static const struct dm_i2c_ops ast_i2c_ops = { + .xfer = ast_i2c_xfer, + .set_bus_speed = ast_i2c_set_speed, + .deblock = ast_i2c_deblock, +}; + +static const struct udevice_id ast_i2c_ids[] = { + { .compatible = "aspeed,ast2400-i2c-bus" }, + { .compatible = "aspeed,ast2500-i2c-bus" }, + { }, +}; + +U_BOOT_DRIVER(ast_i2c) = { + .name = "ast_i2c", + .id = UCLASS_I2C, + .of_match = ast_i2c_ids, + .probe = ast_i2c_probe, + .ofdata_to_platdata = ast_i2c_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct ast_i2c_priv), + .ops = &ast_i2c_ops, +}; diff --git a/drivers/i2c/ast_i2c.h b/drivers/i2c/ast_i2c.h new file mode 100644 index 0000000000..e5dec7a480 --- /dev/null +++ b/drivers/i2c/ast_i2c.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2012-2020 ASPEED Technology Inc. + * Copyright 2016 IBM Corporation + * Copyright 2017 Google, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __AST_I2C_H_ +#define __AST_I2C_H_ + +struct ast_i2c_regs { + u32 fcr; + u32 cactcr1; + u32 cactcr2; + u32 icr; + u32 isr; + u32 csr; + u32 sdar; + u32 pbcr; + u32 trbbr; +#ifdef CONFIG_ASPEED_AST2500 + u32 dma_mbar; + u32 dma_tlr; +#endif +}; + +/* Device Register Definition */ +/* 0x00 : I2CD Function Control Register */ +#define I2CD_BUFF_SEL_MASK (0x7 << 20) +#define I2CD_BUFF_SEL(x) (x << 20) +#define I2CD_M_SDA_LOCK_EN (0x1 << 16) +#define I2CD_MULTI_MASTER_DIS (0x1 << 15) +#define I2CD_M_SCL_DRIVE_EN (0x1 << 14) +#define I2CD_MSB_STS (0x1 << 9) +#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8) +#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) +#define I2CD_M_HIGH_SPEED_EN (0x1 << 6) +#define I2CD_DEF_ADDR_EN (0x1 << 5) +#define I2CD_DEF_ALERT_EN (0x1 << 4) +#define I2CD_DEF_ARP_EN (0x1 << 3) +#define I2CD_DEF_GCALL_EN (0x1 << 2) +#define I2CD_SLAVE_EN (0x1 << 1) +#define I2CD_MASTER_EN (0x1) + +/* 0x04 : I2CD Clock and AC Timing Control Register #1 */ +/* Base register value. These bits are always set by the driver. */ +#define I2CD_CACTC_BASE 0xfff00300 +#define I2CD_TCKHIGH_SHIFT 16 +#define I2CD_TCKLOW_SHIFT 12 +#define I2CD_THDDAT_SHIFT 10 +#define I2CD_TO_DIV_SHIFT 8 +#define I2CD_BASE_DIV_SHIFT 0 + +/* 0x08 : I2CD Clock and AC Timing Control Register #2 */ +#define I2CD_tTIMEOUT 1 +#define I2CD_NO_TIMEOUT_CTRL 0 + +/* 0x0c : I2CD Interrupt Control Register & + * 0x10 : I2CD Interrupt Status Register + * + * These share bit definitions, so use the same values for the enable & + * status bits. + */ +#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) +#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) +#define I2CD_INTR_SMBUS_ALERT (0x1 << 12) +#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11) +#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) +#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) +#define I2CD_INTR_GCALL_ADDR (0x1 << 8) +#define I2CD_INTR_SLAVE_MATCH (0x1 << 7) +#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) +#define I2CD_INTR_ABNORMAL (0x1 << 5) +#define I2CD_INTR_NORMAL_STOP (0x1 << 4) +#define I2CD_INTR_ARBIT_LOSS (0x1 << 3) +#define I2CD_INTR_RX_DONE (0x1 << 2) +#define I2CD_INTR_TX_NAK (0x1 << 1) +#define I2CD_INTR_TX_ACK (0x1 << 0) + +/* 0x14 : I2CD Command/Status Register */ +#define I2CD_SDA_OE (0x1 << 28) +#define I2CD_SDA_O (0x1 << 27) +#define I2CD_SCL_OE (0x1 << 26) +#define I2CD_SCL_O (0x1 << 25) +#define I2CD_TX_TIMING (0x1 << 24) +#define I2CD_TX_STATUS (0x1 << 23) + +/* Tx State Machine */ +#define I2CD_IDLE 0x0 +#define I2CD_MACTIVE 0x8 +#define I2CD_MSTART 0x9 +#define I2CD_MSTARTR 0xa +#define I2CD_MSTOP 0xb +#define I2CD_MTXD 0xc +#define I2CD_MRXACK 0xd +#define I2CD_MRXD 0xe +#define I2CD_MTXACK 0xf +#define I2CD_SWAIT 0x1 +#define I2CD_SRXD 0x4 +#define I2CD_STXACK 0x5 +#define I2CD_STXD 0x6 +#define I2CD_SRXACK 0x7 +#define I2CD_RECOVER 0x3 + +#define I2CD_SCL_LINE_STS (0x1 << 18) +#define I2CD_SDA_LINE_STS (0x1 << 17) +#define I2CD_BUS_BUSY_STS (0x1 << 16) +#define I2CD_SDA_OE_OUT_DIR (0x1 << 15) +#define I2CD_SDA_O_OUT_DIR (0x1 << 14) +#define I2CD_SCL_OE_OUT_DIR (0x1 << 13) +#define I2CD_SCL_O_OUT_DIR (0x1 << 12) +#define I2CD_BUS_RECOVER_CMD (0x1 << 11) +#define I2CD_S_ALT_EN (0x1 << 10) +#define I2CD_RX_DMA_ENABLE (0x1 << 9) +#define I2CD_TX_DMA_ENABLE (0x1 << 8) + +/* Command Bit */ +#define I2CD_RX_BUFF_ENABLE (0x1 << 7) +#define I2CD_TX_BUFF_ENABLE (0x1 << 6) +#define I2CD_M_STOP_CMD (0x1 << 5) +#define I2CD_M_S_RX_CMD_LAST (0x1 << 4) +#define I2CD_M_RX_CMD (0x1 << 3) +#define I2CD_S_TX_CMD (0x1 << 2) +#define I2CD_M_TX_CMD (0x1 << 1) +#define I2CD_M_START_CMD 0x1 + +#define I2CD_RX_DATA_SHIFT 8 +#define I2CD_RX_DATA_MASK (0xff << I2CD_RX_DATA_SHIFT) + +#define I2C_HIGHSPEED_RATE 400000 + +#endif /* __AST_I2C_H_ */ diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 648a96eeb4..3703519aa5 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -37,6 +37,14 @@ DECLARE_GLOBAL_DATA_PTR; #endif /* CONFIG_DM_I2C */ /* + * On SUNXI, we get CONFIG_SYS_TCLK from this include, so we want to + * always have it. + */ +#if defined(CONFIG_DM_I2C) && defined(CONFIG_ARCH_SUNXI) +#include <asm/arch/i2c.h> +#endif + +/* * TWSI register structure */ @@ -831,6 +839,7 @@ static const struct dm_i2c_ops mvtwsi_i2c_ops = { static const struct udevice_id mvtwsi_i2c_ids[] = { { .compatible = "marvell,mv64xxx-i2c", }, { .compatible = "marvell,mv78230-i2c", }, + { .compatible = "allwinner,sun6i-a31-i2c", }, { /* sentinel */ } }; diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index eb789f5bff..13ec0e63b1 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -589,7 +589,7 @@ static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, #endif static struct mxc_i2c_bus mxc_i2c_buses[] = { -#if defined(CONFIG_LS102XA) || defined(CONFIG_VF610) || \ +#if defined(CONFIG_ARCH_LS1021A) || defined(CONFIG_VF610) || \ defined(CONFIG_FSL_LAYERSCAPE) { 0, I2C1_BASE_ADDR, I2C_QUIRK_FLAG }, { 1, I2C2_BASE_ADDR, I2C_QUIRK_FLAG }, diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index af925cecdb..76f41f7e85 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -383,6 +383,7 @@ static const struct udevice_id rockchip_i2c_ids[] = { { .compatible = "rockchip,rk3066-i2c" }, { .compatible = "rockchip,rk3188-i2c" }, { .compatible = "rockchip,rk3288-i2c" }, + { .compatible = "rockchip,rk3399-i2c" }, { } }; diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 609b1fa3fe..309372ab56 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -9,6 +9,15 @@ config LED can provide access to board-specific LEDs. Use of the device tree for configuration is encouraged. +config LED_BLINK + bool "Support LED blinking" + depends on LED + help + Some drivers can support automatic blinking of LEDs with a given + period, without needing timers or extra code to handle the timing. + This option enables support for this which adds slightly to the + code size. + config SPL_LED bool "Enable LED support in SPL" depends on SPL && SPL_DM @@ -17,6 +26,7 @@ config SPL_LED If this is acceptable and you have a need to use LEDs in SPL, enable this option. You will need to enable device tree in SPL for this to work. + config LED_GPIO bool "LED support for GPIO-connected LEDs" depends on LED && DM_GPIO diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index 784ac870e2..78ab76050d 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -22,7 +22,7 @@ int led_get_by_label(const char *label, struct udevice **devp) if (ret) return ret; uclass_foreach_dev(dev, uc) { - struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev); + struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); /* Ignore the top-level LED node */ if (uc_plat->label && !strcmp(label, uc_plat->label)) @@ -32,18 +32,40 @@ int led_get_by_label(const char *label, struct udevice **devp) return -ENODEV; } -int led_set_on(struct udevice *dev, int on) +int led_set_state(struct udevice *dev, enum led_state_t state) { struct led_ops *ops = led_get_ops(dev); - if (!ops->set_on) + if (!ops->set_state) return -ENOSYS; - return ops->set_on(dev, on); + return ops->set_state(dev, state); } +enum led_state_t led_get_state(struct udevice *dev) +{ + struct led_ops *ops = led_get_ops(dev); + + if (!ops->get_state) + return -ENOSYS; + + return ops->get_state(dev); +} + +#ifdef CONFIG_LED_BLINK +int led_set_period(struct udevice *dev, int period_ms) +{ + struct led_ops *ops = led_get_ops(dev); + + if (!ops->set_period) + return -ENOSYS; + + return ops->set_period(dev, period_ms); +} +#endif + UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led", - .per_device_platdata_auto_alloc_size = sizeof(struct led_uclass_plat), + .per_device_platdata_auto_alloc_size = sizeof(struct led_uc_plat), }; diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index 5b119903f5..4106ecb679 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -18,19 +18,47 @@ struct led_gpio_priv { struct gpio_desc gpio; }; -static int gpio_led_set_on(struct udevice *dev, int on) +static int gpio_led_set_state(struct udevice *dev, enum led_state_t state) { struct led_gpio_priv *priv = dev_get_priv(dev); + int ret; + + if (!dm_gpio_is_valid(&priv->gpio)) + return -EREMOTEIO; + switch (state) { + case LEDST_OFF: + case LEDST_ON: + break; + case LEDST_TOGGLE: + ret = dm_gpio_get_value(&priv->gpio); + if (ret < 0) + return ret; + state = !ret; + break; + default: + return -ENOSYS; + } + + return dm_gpio_set_value(&priv->gpio, state); +} + +static enum led_state_t gpio_led_get_state(struct udevice *dev) +{ + struct led_gpio_priv *priv = dev_get_priv(dev); + int ret; if (!dm_gpio_is_valid(&priv->gpio)) return -EREMOTEIO; + ret = dm_gpio_get_value(&priv->gpio); + if (ret < 0) + return ret; - return dm_gpio_set_value(&priv->gpio, on); + return ret ? LEDST_ON : LEDST_OFF; } static int led_gpio_probe(struct udevice *dev) { - struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev); + struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); struct led_gpio_priv *priv = dev_get_priv(dev); /* Ignore the top-level LED node */ @@ -65,7 +93,7 @@ static int led_gpio_bind(struct udevice *parent) for (node = fdt_first_subnode(blob, dev_of_offset(parent)); node > 0; node = fdt_next_subnode(blob, node)) { - struct led_uclass_plat *uc_plat; + struct led_uc_plat *uc_plat; const char *label; label = fdt_getprop(blob, node, "label", NULL); @@ -87,7 +115,8 @@ static int led_gpio_bind(struct udevice *parent) } static const struct led_ops gpio_led_ops = { - .set_on = gpio_led_set_on, + .set_state = gpio_led_set_state, + .get_state = gpio_led_get_state, }; static const struct udevice_id led_gpio_ids[] = { diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e3151ea097..4543cd647e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o obj-$(CONFIG_NS87308) += ns87308.o -obj-$(CONFIG_PDSP188x) += pdsp188x.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o ifdef CONFIG_DM_I2C ifndef CONFIG_SPL_BUILD diff --git a/drivers/misc/pdsp188x.c b/drivers/misc/pdsp188x.c deleted file mode 100644 index aa4351a0ad..0000000000 --- a/drivers/misc/pdsp188x.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010 Sergey Poselenov, Emcraft Systems, <sposelenov@emcraft.com> - * Copyright 2010 Ilya Yanok, Emcraft Systems, <yanok@emcraft.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <led-display.h> -#include <asm/io.h> - -#ifdef CONFIG_CMD_DISPLAY -#define CWORD_CLEAR 0x80 -#define CLEAR_DELAY (110 * 2) -#define DISPLAY_SIZE 8 - -static int pos; /* Current display position */ - -/* Handle different display commands */ -void display_set(int cmd) -{ - if (cmd & DISPLAY_CLEAR) { - out_8((unsigned char *)CONFIG_SYS_DISP_CWORD, CWORD_CLEAR); - udelay(1000 * CLEAR_DELAY); - } - - if (cmd & DISPLAY_HOME) { - pos = 0; - } -} - -/* - * Display a character at the current display position. - * Characters beyond the display size are ignored. - */ -int display_putc(char c) -{ - if (pos >= DISPLAY_SIZE) - return -1; - - out_8((unsigned char *)CONFIG_SYS_DISP_CHR_RAM + pos++, c); - - return c; -} -#endif diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index a61a9e9ca6..de91f1423b 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_GENERIC_MMC) += mmc_legacy.o endif obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o -obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o obj-$(CONFIG_MMC_DW) += dw_mmc.o diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c deleted file mode 100644 index 1627dca3a1..0000000000 --- a/drivers/mmc/bfin_sdh.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Driver for Blackfin on-chip SDH controller - * - * Copyright (c) 2008-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <malloc.h> -#include <part.h> -#include <mmc.h> - -#include <asm/io.h> -#include <linux/errno.h> -#include <asm/byteorder.h> -#include <asm/blackfin.h> -#include <asm/clock.h> -#include <asm/portmux.h> -#include <asm/mach-common/bits/sdh.h> -#include <asm/mach-common/bits/dma.h> - -#if defined(__ADSPBF50x__) || defined(__ADSPBF51x__) || defined(__ADSPBF60x__) -# define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CONTROL -# define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CONTROL -# define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT -# define bfin_write_SDH_COMMAND bfin_write_RSI_COMMAND -# define bfin_read_SDH_RESPONSE0 bfin_read_RSI_RESPONSE0 -# define bfin_read_SDH_RESPONSE1 bfin_read_RSI_RESPONSE1 -# define bfin_read_SDH_RESPONSE2 bfin_read_RSI_RESPONSE2 -# define bfin_read_SDH_RESPONSE3 bfin_read_RSI_RESPONSE3 -# define bfin_write_SDH_DATA_TIMER bfin_write_RSI_DATA_TIMER -# define bfin_write_SDH_DATA_LGTH bfin_write_RSI_DATA_LGTH -# define bfin_read_SDH_DATA_CTL bfin_read_RSI_DATA_CONTROL -# define bfin_write_SDH_DATA_CTL bfin_write_RSI_DATA_CONTROL -# define bfin_read_SDH_STATUS bfin_read_RSI_STATUS -# define bfin_write_SDH_STATUS_CLR bfin_write_RSI_STATUSCL -# define bfin_read_SDH_CFG bfin_read_RSI_CONFIG -# define bfin_write_SDH_CFG bfin_write_RSI_CONFIG -# if defined(__ADSPBF60x__) -# define bfin_read_SDH_BLK_SIZE bfin_read_RSI_BLKSZ -# define bfin_write_SDH_BLK_SIZE bfin_write_RSI_BLKSZ -# define bfin_write_DMA_START_ADDR bfin_write_DMA10_START_ADDR -# define bfin_write_DMA_X_COUNT bfin_write_DMA10_X_COUNT -# define bfin_write_DMA_X_MODIFY bfin_write_DMA10_X_MODIFY -# define bfin_write_DMA_CONFIG bfin_write_DMA10_CONFIG -# else -# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CONTROL -# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CONTROL -# define bfin_write_DMA_START_ADDR bfin_write_DMA4_START_ADDR -# define bfin_write_DMA_X_COUNT bfin_write_DMA4_X_COUNT -# define bfin_write_DMA_X_MODIFY bfin_write_DMA4_X_MODIFY -# define bfin_write_DMA_CONFIG bfin_write_DMA4_CONFIG -# endif -# define PORTMUX_PINS \ - { P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3, P_RSI_CMD, P_RSI_CLK, 0 } -#elif defined(__ADSPBF54x__) -# define bfin_write_DMA_START_ADDR bfin_write_DMA22_START_ADDR -# define bfin_write_DMA_X_COUNT bfin_write_DMA22_X_COUNT -# define bfin_write_DMA_X_MODIFY bfin_write_DMA22_X_MODIFY -# define bfin_write_DMA_CONFIG bfin_write_DMA22_CONFIG -# define PORTMUX_PINS \ - { P_SD_D0, P_SD_D1, P_SD_D2, P_SD_D3, P_SD_CLK, P_SD_CMD, 0 } -#else -# error no support for this proc yet -#endif - -static int -sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) -{ - unsigned int status, timeout; - int cmd = mmc_cmd->cmdidx; - int flags = mmc_cmd->resp_type; - int arg = mmc_cmd->cmdarg; - int ret; - u16 sdh_cmd; - - sdh_cmd = cmd | CMD_E; - if (flags & MMC_RSP_PRESENT) - sdh_cmd |= CMD_RSP; - if (flags & MMC_RSP_136) - sdh_cmd |= CMD_L_RSP; -#ifdef RSI_BLKSZ - sdh_cmd |= CMD_DATA0_BUSY; -#endif - - bfin_write_SDH_ARGUMENT(arg); - bfin_write_SDH_COMMAND(sdh_cmd); - - /* wait for a while */ - timeout = 0; - do { - if (++timeout > 1000000) { - status = CMD_TIME_OUT; - break; - } - udelay(1); - status = bfin_read_SDH_STATUS(); - } while (!(status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | - CMD_CRC_FAIL))); - - if (flags & MMC_RSP_PRESENT) { - mmc_cmd->response[0] = bfin_read_SDH_RESPONSE0(); - if (flags & MMC_RSP_136) { - mmc_cmd->response[1] = bfin_read_SDH_RESPONSE1(); - mmc_cmd->response[2] = bfin_read_SDH_RESPONSE2(); - mmc_cmd->response[3] = bfin_read_SDH_RESPONSE3(); - } - } - - if (status & CMD_TIME_OUT) - ret = -ETIMEDOUT; - else if (status & CMD_CRC_FAIL && flags & MMC_RSP_CRC) - ret = -ECOMM; - else - ret = 0; - - bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | - CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); -#ifdef RSI_BLKSZ - /* wait till card ready */ - while (!(bfin_read_RSI_ESTAT() & SD_CARD_READY)) - continue; - bfin_write_RSI_ESTAT(SD_CARD_READY); -#endif - - return ret; -} - -/* set data for single block transfer */ -static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data) -{ - u16 data_ctl = 0; - u16 dma_cfg = 0; - unsigned long data_size = data->blocksize * data->blocks; - - /* Don't support write yet. */ - if (data->flags & MMC_DATA_WRITE) - return -EOPNOTSUPP; -#ifndef RSI_BLKSZ - data_ctl |= ((ffs(data->blocksize) - 1) << 4); -#else - bfin_write_SDH_BLK_SIZE(data->blocksize); -#endif - data_ctl |= DTX_DIR; - bfin_write_SDH_DATA_CTL(data_ctl); - dma_cfg = WDSIZE_32 | PSIZE_32 | RESTART | WNR | DMAEN; - - bfin_write_SDH_DATA_TIMER(-1); - - blackfin_dcache_flush_invalidate_range(data->dest, - data->dest + data_size); - /* configure DMA */ - bfin_write_DMA_START_ADDR(data->dest); - bfin_write_DMA_X_COUNT(data_size / 4); - bfin_write_DMA_X_MODIFY(4); - bfin_write_DMA_CONFIG(dma_cfg); - bfin_write_SDH_DATA_LGTH(data_size); - /* kick off transfer */ - bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); - - return 0; -} - - -static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - u32 status; - int ret = 0; - - if (data) { - ret = sdh_setup_data(mmc, data); - if (ret) - return ret; - } - - ret = sdh_send_cmd(mmc, cmd); - if (ret) { - bfin_write_SDH_COMMAND(0); - bfin_write_DMA_CONFIG(0); - bfin_write_SDH_DATA_CTL(0); - SSYNC(); - printf("sending CMD%d failed\n", cmd->cmdidx); - return ret; - } - - if (data) { - do { - udelay(1); - status = bfin_read_SDH_STATUS(); - } while (!(status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | - RX_OVERRUN))); - - if (status & DAT_TIME_OUT) { - bfin_write_SDH_STATUS_CLR(DAT_TIMEOUT_STAT); - ret = -ETIMEDOUT; - } else if (status & (DAT_CRC_FAIL | RX_OVERRUN)) { - bfin_write_SDH_STATUS_CLR(DAT_CRC_FAIL_STAT | RX_OVERRUN_STAT); - ret = -ECOMM; - } else - bfin_write_SDH_STATUS_CLR(DAT_BLK_END_STAT | DAT_END_STAT); - - if (ret) { - printf("tranfering data failed\n"); - return ret; - } - } - return 0; -} - -static void sdh_set_clk(unsigned long clk) -{ - unsigned long sys_clk; - unsigned long clk_div; - u16 clk_ctl = 0; - - clk_ctl = bfin_read_SDH_CLK_CTL(); - if (clk) { - /* setting SD_CLK */ - sys_clk = get_sclk(); - bfin_write_SDH_CLK_CTL(clk_ctl & ~CLK_E); - if (sys_clk % (2 * clk) == 0) - clk_div = sys_clk / (2 * clk) - 1; - else - clk_div = sys_clk / (2 * clk); - - if (clk_div > 0xff) - clk_div = 0xff; - clk_ctl |= (clk_div & 0xff); - clk_ctl |= CLK_E; - bfin_write_SDH_CLK_CTL(clk_ctl); - } else - bfin_write_SDH_CLK_CTL(clk_ctl & ~CLK_E); -} - -static int bfin_sdh_set_ios(struct mmc *mmc) -{ - u16 cfg = 0; - u16 clk_ctl = 0; - - if (mmc->bus_width == 4) { - cfg = bfin_read_SDH_CFG(); -#ifndef RSI_BLKSZ - cfg &= ~PD_SDDAT3; -#endif - cfg |= PUP_SDDAT3; - bfin_write_SDH_CFG(cfg); - clk_ctl |= WIDE_BUS_4; - } - bfin_write_SDH_CLK_CTL(clk_ctl); - sdh_set_clk(mmc->clock); - - return 0; -} - -static int bfin_sdh_init(struct mmc *mmc) -{ - const unsigned short pins[] = PORTMUX_PINS; - int ret; - - /* Initialize sdh controller */ - ret = peripheral_request_list(pins, "bfin_sdh"); - if (ret < 0) - return ret; -#if defined(__ADSPBF54x__) - bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); -#endif - bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); - /* Disable card detect pin */ - bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | 0x60); -#ifndef RSI_BLKSZ - bfin_write_SDH_PWR_CTL(PWR_ON | ROD_CTL); -#else - bfin_write_SDH_CFG(bfin_read_SDH_CFG() | PWR_ON); -#endif - return 0; -} - -static const struct mmc_ops bfin_mmc_ops = { - .send_cmd = bfin_sdh_request, - .set_ios = bfin_sdh_set_ios, - .init = bfin_sdh_init, -}; - -static struct mmc_config bfin_mmc_cfg = { - .name = "Blackfin SDH", - .ops = &bfin_mmc_ops, - .host_caps = MMC_MODE_4BIT, - .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, -}; - -int bfin_mmc_init(bd_t *bis) -{ - struct mmc *mmc; - - bfin_mmc_cfg.f_max = get_sclk(); - bfin_mmc_cfg.f_min = bfin_mmc_cfg.f_max >> 9; - - mmc = mmc_create(&bfin_mmc_cfg, NULL); - if (mmc == NULL) - return -1; - - return 0; -} diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index fd4bb66f50..82358f674b 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -42,7 +42,6 @@ obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o -obj-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_NAND_DENALI) += denali.o obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/am335x_spl_bch.c index 5b189a1d8a..e68b4a5b19 100644 --- a/drivers/mtd/nand/am335x_spl_bch.c +++ b/drivers/mtd/nand/am335x_spl_bch.c @@ -198,53 +198,6 @@ static int nand_read_page(int block, int page, void *dst) return 0; } -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page, page_offset; - - /* - * offs has to be aligned to a page address! - */ - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - page_offset = offs % CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - /* - * Skip bad blocks - */ - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - /* - * When offs is not aligned to page address the - * extra offset is copied to dst as well. Copy - * the image such that its first byte will be - * at the dst. - */ - if (unlikely(page_offset)) { - memmove(dst, dst + page_offset, - CONFIG_SYS_NAND_PAGE_SIZE); - dst = (void *)((int)dst - page_offset); - page_offset = 0; - } - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - /* nand_init() - initialize data to make nand usable by SPL */ void nand_init(void) { @@ -269,3 +222,5 @@ void nand_deselect(void) if (nand_chip.select_chip) nand_chip.select_chip(mtd, -1); } + +#include "nand_spl_loaders.c" diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 21d5d0e70d..7c10bfedc6 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1380,34 +1380,6 @@ static int nand_read_page(int block, int page, void *dst) } #endif /* CONFIG_SPL_NAND_ECC */ -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page; - - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - int at91_nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd_to_nand(mtd); @@ -1474,6 +1446,8 @@ void nand_deselect(void) nand_chip.select_chip(mtd, -1); } +#include "nand_spl_loaders.c" + #else #ifndef CONFIG_SYS_NAND_BASE_LIST diff --git a/drivers/mtd/nand/bfin_nand.c b/drivers/mtd/nand/bfin_nand.c deleted file mode 100644 index 7c11868cd3..0000000000 --- a/drivers/mtd/nand/bfin_nand.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Driver for Blackfin on-chip NAND controller. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Copyright (c) 2007-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -/* TODO: - * - move bit defines into mach-common/bits/nand.h - * - try and replace all IRQSTAT usage with STAT polling - * - have software ecc mode use same algo as hw ecc ? - */ - -#include <common.h> -#include <console.h> -#include <asm/io.h> - -#ifdef DEBUG -# define pr_stamp() printf("%s:%s:%i: here i am\n", __FILE__, __func__, __LINE__) -#else -# define pr_stamp() -#endif - -#include <nand.h> - -#include <asm/blackfin.h> -#include <asm/portmux.h> - -/* Bit masks for NFC_CTL */ - -#define WR_DLY 0xf /* Write Strobe Delay */ -#define RD_DLY 0xf0 /* Read Strobe Delay */ -#define NWIDTH 0x100 /* NAND Data Width */ -#define PG_SIZE 0x200 /* Page Size */ - -/* Bit masks for NFC_STAT */ - -#define NBUSY 0x1 /* Not Busy */ -#define WB_FULL 0x2 /* Write Buffer Full */ -#define PG_WR_STAT 0x4 /* Page Write Pending */ -#define PG_RD_STAT 0x8 /* Page Read Pending */ -#define WB_EMPTY 0x10 /* Write Buffer Empty */ - -/* Bit masks for NFC_IRQSTAT */ - -#define NBUSYIRQ 0x1 /* Not Busy IRQ */ -#define WB_OVF 0x2 /* Write Buffer Overflow */ -#define WB_EDGE 0x4 /* Write Buffer Edge Detect */ -#define RD_RDY 0x8 /* Read Data Ready */ -#define WR_DONE 0x10 /* Page Write Done */ - -#define NAND_IS_512() (CONFIG_BFIN_NFC_CTL_VAL & 0x200) - -/* - * hardware specific access to control-lines - */ -static void bfin_nfc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - pr_stamp(); - - if (cmd == NAND_CMD_NONE) - return; - - while (bfin_read_NFC_STAT() & WB_FULL) - continue; - - if (ctrl & NAND_CLE) - bfin_write_NFC_CMD(cmd); - else - bfin_write_NFC_ADDR(cmd); - SSYNC(); -} - -static int bfin_nfc_devready(struct mtd_info *mtd) -{ - pr_stamp(); - return (bfin_read_NFC_STAT() & NBUSY) ? 1 : 0; -} - -/* - * PIO mode for buffer writing and reading - */ -static void bfin_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - pr_stamp(); - - int i; - - /* - * Data reads are requested by first writing to NFC_DATA_RD - * and then reading back from NFC_READ. - */ - for (i = 0; i < len; ++i) { - while (bfin_read_NFC_STAT() & WB_FULL) - if (ctrlc()) - return; - - /* Contents do not matter */ - bfin_write_NFC_DATA_RD(0x0000); - SSYNC(); - - while (!(bfin_read_NFC_IRQSTAT() & RD_RDY)) - if (ctrlc()) - return; - - buf[i] = bfin_read_NFC_READ(); - - bfin_write_NFC_IRQSTAT(RD_RDY); - } -} - -static uint8_t bfin_nfc_read_byte(struct mtd_info *mtd) -{ - pr_stamp(); - - uint8_t val; - bfin_nfc_read_buf(mtd, &val, 1); - return val; -} - -static void bfin_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - pr_stamp(); - - int i; - - for (i = 0; i < len; ++i) { - while (bfin_read_NFC_STAT() & WB_FULL) - if (ctrlc()) - return; - - bfin_write_NFC_DATA_WR(buf[i]); - } - - /* Wait for the buffer to drain before we return */ - while (!(bfin_read_NFC_STAT() & WB_EMPTY)) - if (ctrlc()) - return; -} - -/* - * ECC functions - * These allow the bfin to use the controller's ECC - * generator block to ECC the data as it passes through - */ - -/* - * ECC error correction function - */ -static int bfin_nfc_correct_data_256(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - u32 syndrome[5]; - u32 calced, stored; - unsigned short failing_bit, failing_byte; - u_char data; - - pr_stamp(); - - calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); - stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); - - syndrome[0] = (calced ^ stored); - - /* - * syndrome 0: all zero - * No error in data - * No action - */ - if (!syndrome[0] || !calced || !stored) - return 0; - - /* - * sysdrome 0: only one bit is one - * ECC data was incorrect - * No action - */ - if (hweight32(syndrome[0]) == 1) - return 1; - - syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); - syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); - syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); - syndrome[4] = syndrome[2] ^ syndrome[3]; - - /* - * sysdrome 0: exactly 11 bits are one, each parity - * and parity' pair is 1 & 0 or 0 & 1. - * 1-bit correctable error - * Correct the error - */ - if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { - failing_bit = syndrome[1] & 0x7; - failing_byte = syndrome[1] >> 0x3; - data = *(dat + failing_byte); - data = data ^ (0x1 << failing_bit); - *(dat + failing_byte) = data; - - return 0; - } - - /* - * sysdrome 0: random data - * More than 1-bit error, non-correctable error - * Discard data, mark bad block - */ - - return 1; -} - -static int bfin_nfc_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - int ret; - - pr_stamp(); - - ret = bfin_nfc_correct_data_256(mtd, dat, read_ecc, calc_ecc); - - /* If page size is 512, correct second 256 bytes */ - if (NAND_IS_512()) { - dat += 256; - read_ecc += 8; - calc_ecc += 8; - ret |= bfin_nfc_correct_data_256(mtd, dat, read_ecc, calc_ecc); - } - - return ret; -} - -static void reset_ecc(void) -{ - bfin_write_NFC_RST(0x1); - while (bfin_read_NFC_RST() & 1) - continue; -} - -static void bfin_nfc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - reset_ecc(); -} - -static int bfin_nfc_calculate_ecc(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) -{ - u16 ecc0, ecc1; - u32 code[2]; - u8 *p; - - pr_stamp(); - - /* first 4 bytes ECC code for 256 page size */ - ecc0 = bfin_read_NFC_ECC0(); - ecc1 = bfin_read_NFC_ECC1(); - - code[0] = (ecc0 & 0x7FF) | ((ecc1 & 0x7FF) << 11); - - /* first 3 bytes in ecc_code for 256 page size */ - p = (u8 *) code; - memcpy(ecc_code, p, 3); - - /* second 4 bytes ECC code for 512 page size */ - if (NAND_IS_512()) { - ecc0 = bfin_read_NFC_ECC2(); - ecc1 = bfin_read_NFC_ECC3(); - code[1] = (ecc0 & 0x7FF) | ((ecc1 & 0x7FF) << 11); - - /* second 3 bytes in ecc_code for second 256 - * bytes of 512 page size - */ - p = (u8 *) (code + 1); - memcpy((ecc_code + 3), p, 3); - } - - reset_ecc(); - - return 0; -} - -#ifdef CONFIG_BFIN_NFC_BOOTROM_ECC -# define BOOTROM_ECC 1 -#else -# define BOOTROM_ECC 0 -#endif - -static uint8_t bbt_pattern[] = { 0xff }; - -static struct nand_bbt_descr bootrom_bbt = { - .options = 0, - .offs = 63, - .len = 1, - .pattern = bbt_pattern, -}; - -static struct nand_ecclayout bootrom_ecclayout = { - .eccbytes = 24, - .eccpos = { - 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, - 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, - 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, - 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, - 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, - 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, - 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, - 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 - }, - .oobfree = { - { 0x8 * 0 + 3, 5 }, - { 0x8 * 1 + 3, 5 }, - { 0x8 * 2 + 3, 5 }, - { 0x8 * 3 + 3, 5 }, - { 0x8 * 4 + 3, 5 }, - { 0x8 * 5 + 3, 5 }, - { 0x8 * 6 + 3, 5 }, - { 0x8 * 7 + 3, 5 }, - } -}; - -/* - * Board-specific NAND initialization. The following members of the - * argument are board-specific (per include/linux/mtd/nand.h): - * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device - * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device - * - cmd_ctrl: hardwarespecific function for accesing control-lines - * - dev_ready: hardwarespecific function for accesing device ready/busy line - * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must - * only be provided if a hardware ECC is available - * - ecc.mode: mode of ecc, see defines - * - chip_delay: chip dependent delay for transfering data from array to - * read regs (tR) - * - options: various chip options. They can partly be set to inform - * nand_scan about special functionality. See the defines for further - * explanation - * Members with a "?" were not set in the merged testing-NAND branch, - * so they are not set here either. - */ -int board_nand_init(struct nand_chip *chip) -{ - const unsigned short pins[] = { - P_NAND_CE, P_NAND_RB, P_NAND_D0, P_NAND_D1, P_NAND_D2, - P_NAND_D3, P_NAND_D4, P_NAND_D5, P_NAND_D6, P_NAND_D7, - P_NAND_WE, P_NAND_RE, P_NAND_CLE, P_NAND_ALE, 0, - }; - - pr_stamp(); - - /* set width/ecc/timings/etc... */ - bfin_write_NFC_CTL(CONFIG_BFIN_NFC_CTL_VAL); - - /* clear interrupt status */ - bfin_write_NFC_IRQMASK(0x0); - bfin_write_NFC_IRQSTAT(0xffff); - - /* enable GPIO function enable register */ - peripheral_request_list(pins, "bfin_nand"); - - chip->cmd_ctrl = bfin_nfc_cmd_ctrl; - chip->read_buf = bfin_nfc_read_buf; - chip->write_buf = bfin_nfc_write_buf; - chip->read_byte = bfin_nfc_read_byte; - -#ifdef CONFIG_BFIN_NFC_NO_HW_ECC -# define ECC_HW 0 -#else -# define ECC_HW 1 -#endif - if (ECC_HW) { - if (BOOTROM_ECC) { - chip->badblock_pattern = &bootrom_bbt; - chip->ecc.layout = &bootrom_ecclayout; - } - if (!NAND_IS_512()) { - chip->ecc.bytes = 3; - chip->ecc.size = 256; - chip->ecc.strength = 1; - } else { - chip->ecc.bytes = 6; - chip->ecc.size = 512; - chip->ecc.strength = 2; - } - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.calculate = bfin_nfc_calculate_ecc; - chip->ecc.correct = bfin_nfc_correct_data; - chip->ecc.hwctl = bfin_nfc_enable_hwecc; - } else - chip->ecc.mode = NAND_ECC_SOFT; - chip->dev_ready = bfin_nfc_devready; - chip->chip_delay = 0; - - return 0; -} diff --git a/drivers/mtd/nand/nand_spl_loaders.c b/drivers/mtd/nand/nand_spl_loaders.c new file mode 100644 index 0000000000..177c12b581 --- /dev/null +++ b/drivers/mtd/nand/nand_spl_loaders.c @@ -0,0 +1,104 @@ +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{ + unsigned int block, lastblock; + unsigned int page, page_offset; + + /* offs has to be aligned to a page address! */ + block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; + lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; + page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; + page_offset = offs % CONFIG_SYS_NAND_PAGE_SIZE; + + while (block <= lastblock) { + if (!nand_is_bad_block(block)) { + /* Skip bad blocks */ + while (page < CONFIG_SYS_NAND_PAGE_COUNT) { + nand_read_page(block, page, dst); + /* + * When offs is not aligned to page address the + * extra offset is copied to dst as well. Copy + * the image such that its first byte will be + * at the dst. + */ + if (unlikely(page_offset)) { + memmove(dst, dst + page_offset, + CONFIG_SYS_NAND_PAGE_SIZE); + dst = (void *)((int)dst - page_offset); + page_offset = 0; + } + dst += CONFIG_SYS_NAND_PAGE_SIZE; + page++; + } + + page = 0; + } else { + lastblock++; + } + + block++; + } + + return 0; +} + +#ifdef CONFIG_SPL_UBI +/* + * Temporary storage for non NAND page aligned and non NAND page sized + * reads. Note: This does not support runtime detected FLASH yet, but + * that should be reasonably easy to fix by making the buffer large + * enough :) + */ +static u8 scratch_buf[CONFIG_SYS_NAND_PAGE_SIZE]; + +/** + * nand_spl_read_block - Read data from physical eraseblock into a buffer + * @block: Number of the physical eraseblock + * @offset: Data offset from the start of @peb + * @len: Data size to read + * @dst: Address of the destination buffer + * + * This could be further optimized if we'd have a subpage read + * function in the simple code. On NAND which allows subpage reads + * this would spare quite some time to readout e.g. the VID header of + * UBI. + * + * Notes: + * @offset + @len are not allowed to be larger than a physical + * erase block. No sanity check done for simplicity reasons. + * + * To support runtime detected flash this needs to be extended by + * information about the actual flash geometry, but thats beyond the + * scope of this effort and for most applications where fast boot is + * required it is not an issue anyway. + */ +int nand_spl_read_block(int block, int offset, int len, void *dst) +{ + int page, read; + + /* Calculate the page number */ + page = offset / CONFIG_SYS_NAND_PAGE_SIZE; + + /* Offset to the start of a flash page */ + offset = offset % CONFIG_SYS_NAND_PAGE_SIZE; + + while (len) { + /* + * Non page aligned reads go to the scratch buffer. + * Page aligned reads go directly to the destination. + */ + if (offset || len < CONFIG_SYS_NAND_PAGE_SIZE) { + nand_read_page(block, page, scratch_buf); + read = min(len, CONFIG_SYS_NAND_PAGE_SIZE - offset); + memcpy(dst, scratch_buf + offset, read); + offset = 0; + } else { + nand_read_page(block, page, dst); + read = CONFIG_SYS_NAND_PAGE_SIZE; + } + page++; + len -= read; + dst += read; + } + return 0; +} +#endif diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/nand_spl_simple.c index 55f48d3a14..56e86d1760 100644 --- a/drivers/mtd/nand/nand_spl_simple.c +++ b/drivers/mtd/nand/nand_spl_simple.c @@ -209,102 +209,6 @@ static int nand_read_page(int block, int page, void *dst) } #endif -#ifdef CONFIG_SPL_UBI -/* - * Temporary storage for non NAND page aligned and non NAND page sized - * reads. Note: This does not support runtime detected FLASH yet, but - * that should be reasonably easy to fix by making the buffer large - * enough :) - */ -static u8 scratch_buf[CONFIG_SYS_NAND_PAGE_SIZE]; - -/** - * nand_spl_read_block - Read data from physical eraseblock into a buffer - * @block: Number of the physical eraseblock - * @offset: Data offset from the start of @peb - * @len: Data size to read - * @dst: Address of the destination buffer - * - * This could be further optimized if we'd have a subpage read - * function in the simple code. On NAND which allows subpage reads - * this would spare quite some time to readout e.g. the VID header of - * UBI. - * - * Notes: - * @offset + @len are not allowed to be larger than a physical - * erase block. No sanity check done for simplicity reasons. - * - * To support runtime detected flash this needs to be extended by - * information about the actual flash geometry, but thats beyond the - * scope of this effort and for most applications where fast boot is - * required it is not an issue anyway. - */ -int nand_spl_read_block(int block, int offset, int len, void *dst) -{ - int page, read; - - /* Calculate the page number */ - page = offset / CONFIG_SYS_NAND_PAGE_SIZE; - - /* Offset to the start of a flash page */ - offset = offset % CONFIG_SYS_NAND_PAGE_SIZE; - - while (len) { - /* - * Non page aligned reads go to the scratch buffer. - * Page aligned reads go directly to the destination. - */ - if (offset || len < CONFIG_SYS_NAND_PAGE_SIZE) { - nand_read_page(block, page, scratch_buf); - read = min(len, CONFIG_SYS_NAND_PAGE_SIZE - offset); - memcpy(dst, scratch_buf + offset, read); - offset = 0; - } else { - nand_read_page(block, page, dst); - read = CONFIG_SYS_NAND_PAGE_SIZE; - } - page++; - len -= read; - dst += read; - } - return 0; -} -#endif - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page; - - /* - * offs has to be aligned to a page address! - */ - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - /* - * Skip bad blocks - */ - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - /* nand_init() - initialize data to make nand usable by SPL */ void nand_init(void) { @@ -333,3 +237,5 @@ void nand_deselect(void) if (nand_chip.select_chip) nand_chip.select_chip(mtd, -1); } + +#include "nand_spl_loaders.c" diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8aa92790f4..9cd0d94cbd 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -149,6 +149,12 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation. +config RGMII + bool "Enable RGMII" + help + Enable the support of the Reduced Gigabit Media-Independent + Interface (RGMII). + config RTL8139 bool "Realtek 8139 series Ethernet controller driver" help @@ -161,6 +167,17 @@ config RTL8169 This driver supports Realtek 8169 series gigabit ethernet family of PCI/PCIe chipsets/adapters. +config SUN7I_GMAC + bool "Enable Allwinner GMAC Ethernet support" + help + Enable the support for Sun7i GMAC Ethernet controller + +config SUN4I_EMAC + bool "Allwinner Sun4i Ethernet MAC support" + depends on DM_ETH + help + This driver supports the Allwinner based SUN4I Ethernet MAC. + config SUN8I_EMAC bool "Allwinner Sun8i Ethernet MAC support" depends on DM_ETH diff --git a/drivers/net/Makefile b/drivers/net/Makefile index ac7e07bfdf..aedb2cc90d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o obj-$(CONFIG_DRIVER_AX88180) += ax88180.o obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o -obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o obj-$(CONFIG_CS8900) += cs8900.o obj-$(CONFIG_TULIP) += dc2114x.o diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c deleted file mode 100644 index 26a626b4cb..0000000000 --- a/drivers/net/bfin_mac.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Driver for Blackfin On-Chip MAC device - * - * Copyright (c) 2005-2008 Analog Device, Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <config.h> -#include <net.h> -#include <netdev.h> -#include <command.h> -#include <malloc.h> -#include <miiphy.h> -#include <linux/mdio.h> -#include <linux/mii.h> - -#include <asm/blackfin.h> -#include <asm/clock.h> -#include <asm/portmux.h> -#include <asm/mach-common/bits/dma.h> -#include <asm/mach-common/bits/emac.h> -#include <asm/mach-common/bits/pll.h> - -#include "bfin_mac.h" - -#ifndef CONFIG_PHY_ADDR -# define CONFIG_PHY_ADDR 1 -#endif -#ifndef CONFIG_PHY_CLOCK_FREQ -# define CONFIG_PHY_CLOCK_FREQ 2500000 -#endif - -#ifdef CONFIG_POST -#include <post.h> -#endif - -#define RXBUF_BASE_ADDR 0xFF900000 -#define TXBUF_BASE_ADDR 0xFF800000 -#define TX_BUF_CNT 1 - -#define TOUT_LOOP 1000000 - -static ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT]; -static ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX]; -static u16 txIdx; /* index of the current RX buffer */ -static u16 rxIdx; /* index of the current TX buffer */ - -/* DMAx_CONFIG values at DMA Restart */ -static const union { - u16 data; - ADI_DMA_CONFIG_REG reg; -} txdmacfg = { - .reg = { - .b_DMA_EN = 1, /* enabled */ - .b_WNR = 0, /* read from memory */ - .b_WDSIZE = 2, /* wordsize is 32 bits */ - .b_DMA2D = 0, - .b_RESTART = 0, - .b_DI_SEL = 0, - .b_DI_EN = 0, /* no interrupt */ - .b_NDSIZE = 5, /* 5 half words is desc size */ - .b_FLOW = 7 /* large desc flow */ - }, -}; - -static int bfin_miiphy_wait(void) -{ - /* poll the STABUSY bit */ - while (bfin_read_EMAC_STAADD() & STABUSY) - continue; - return 0; -} - -static int bfin_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - ushort val = 0; - if (bfin_miiphy_wait()) - return 1; - bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY); - if (bfin_miiphy_wait()) - return 1; - val = bfin_read_EMAC_STADAT(); - return val; -} - -static int bfin_miiphy_write(struct mii_dev *bus, int addr, int devad, - int reg, u16 val) -{ - if (bfin_miiphy_wait()) - return 1; - bfin_write_EMAC_STADAT(val); - bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY); - return 0; -} - -int bfin_EMAC_initialize(bd_t *bis) -{ - struct eth_device *dev; - dev = malloc(sizeof(*dev)); - if (dev == NULL) - hang(); - - memset(dev, 0, sizeof(*dev)); - strcpy(dev->name, "bfin_mac"); - - dev->iobase = 0; - dev->priv = 0; - dev->init = bfin_EMAC_init; - dev->halt = bfin_EMAC_halt; - dev->send = bfin_EMAC_send; - dev->recv = bfin_EMAC_recv; - dev->write_hwaddr = bfin_EMAC_setup_addr; - - eth_register(dev); - -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) - return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); - mdiodev->read = bfin_miiphy_read; - mdiodev->write = bfin_miiphy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; - - dev->priv = mdiodev; -#endif - - return 0; -} - -static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length) -{ - int i; - int result = 0; - - if (length <= 0) { - printf("Ethernet: bad packet size: %d\n", length); - goto out; - } - - if (bfin_read_DMA2_IRQ_STATUS() & DMA_ERR) { - printf("Ethernet: tx DMA error\n"); - goto out; - } - - for (i = 0; (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN); ++i) { - if (i > TOUT_LOOP) { - puts("Ethernet: tx time out\n"); - goto out; - } - } - txbuf[txIdx]->FrmData->NoBytes = length; - memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length); - txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData; - bfin_write_DMA2_NEXT_DESC_PTR(txbuf[txIdx]->Dma); - bfin_write_DMA2_CONFIG(txdmacfg.data); - bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE); - - for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) { - if (i > TOUT_LOOP) { - puts("Ethernet: tx error\n"); - goto out; - } - } - result = txbuf[txIdx]->StatusWord; - txbuf[txIdx]->StatusWord = 0; - if ((txIdx + 1) >= TX_BUF_CNT) - txIdx = 0; - else - txIdx++; - out: - debug("BFIN EMAC send: length = %d\n", length); - return result; -} - -static int bfin_EMAC_recv(struct eth_device *dev) -{ - int length = 0; - - for (;;) { - if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) { - length = -1; - break; - } - if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) { - printf("Ethernet: rx dma overrun\n"); - break; - } - if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) { - printf("Ethernet: rx error\n"); - break; - } - length = rxbuf[rxIdx]->StatusWord & 0x000007FF; - if (length <= 4) { - printf("Ethernet: bad frame\n"); - break; - } - - debug("%s: len = %d\n", __func__, length - 4); - - net_rx_packets[rxIdx] = rxbuf[rxIdx]->FrmData->Dest; - net_process_received_packet(net_rx_packets[rxIdx], length - 4); - bfin_write_DMA1_IRQ_STATUS(DMA_DONE | DMA_ERR); - rxbuf[rxIdx]->StatusWord = 0x00000000; - if ((rxIdx + 1) >= PKTBUFSRX) - rxIdx = 0; - else - rxIdx++; - } - - return length; -} - -/************************************************************** - * - * Ethernet Initialization Routine - * - *************************************************************/ - -/* MDC = SCLK / MDC_freq / 2 - 1 */ -#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1) - -#ifndef CONFIG_BFIN_MAC_PINS -# ifdef CONFIG_RMII -# define CONFIG_BFIN_MAC_PINS P_RMII0 -# else -# define CONFIG_BFIN_MAC_PINS P_MII0 -# endif -#endif - -static int bfin_miiphy_init(struct eth_device *dev, int *opmode) -{ - const unsigned short pins[] = CONFIG_BFIN_MAC_PINS; - int phydat; - size_t count; - struct mii_dev *mdiodev = dev->priv; - - /* Enable PHY output */ - bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE); - - /* Set all the pins to peripheral mode */ - peripheral_request_list(pins, "bfin_mac"); - - /* Odd word alignment for Receive Frame DMA word */ - /* Configure checksum support and rcve frame word alignment */ - bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ))); - - /* turn on auto-negotiation and wait for link to come up */ - bfin_miiphy_write(mdiodev, CONFIG_PHY_ADDR, MDIO_DEVAD_NONE, MII_BMCR, - BMCR_ANENABLE); - count = 0; - while (1) { - ++count; - phydat = bfin_miiphy_read(mdiodev, CONFIG_PHY_ADDR, - MDIO_DEVAD_NONE, MII_BMSR); - if (phydat < 0) - return phydat; - if (phydat & BMSR_LSTATUS) - break; - if (count > 30000) { - printf("%s: link down, check cable\n", dev->name); - return -1; - } - udelay(100); - } - - /* see what kind of link we have */ - phydat = bfin_miiphy_read(mdiodev, CONFIG_PHY_ADDR, MDIO_DEVAD_NONE, - MII_LPA); - if (phydat < 0) - return phydat; - if (phydat & LPA_DUPLEX) - *opmode = FDMODE; - else - *opmode = 0; - - bfin_write_EMAC_MMC_CTL(RSTC | CROLL); - bfin_write_EMAC_VLAN1(EMAC_VLANX_DEF_VAL); - bfin_write_EMAC_VLAN2(EMAC_VLANX_DEF_VAL); - - /* Initialize the TX DMA channel registers */ - bfin_write_DMA2_X_COUNT(0); - bfin_write_DMA2_X_MODIFY(4); - bfin_write_DMA2_Y_COUNT(0); - bfin_write_DMA2_Y_MODIFY(0); - - /* Initialize the RX DMA channel registers */ - bfin_write_DMA1_X_COUNT(0); - bfin_write_DMA1_X_MODIFY(4); - bfin_write_DMA1_Y_COUNT(0); - bfin_write_DMA1_Y_MODIFY(0); - - return 0; -} - -static int bfin_EMAC_setup_addr(struct eth_device *dev) -{ - bfin_write_EMAC_ADDRLO( - dev->enetaddr[0] | - dev->enetaddr[1] << 8 | - dev->enetaddr[2] << 16 | - dev->enetaddr[3] << 24 - ); - bfin_write_EMAC_ADDRHI( - dev->enetaddr[4] | - dev->enetaddr[5] << 8 - ); - return 0; -} - -static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) -{ - u32 opmode; - int dat; - int i; - debug("Eth_init: ......\n"); - - txIdx = 0; - rxIdx = 0; - - /* Initialize System Register */ - if (bfin_miiphy_init(dev, &dat) < 0) - return -1; - - /* Initialize EMAC address */ - bfin_EMAC_setup_addr(dev); - - /* Initialize TX and RX buffer */ - for (i = 0; i < PKTBUFSRX; i++) { - rxbuf[i] = SetupRxBuffer(i); - if (i > 0) { - rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = rxbuf[i]->Dma; - if (i == (PKTBUFSRX - 1)) - rxbuf[i]->Dma[1].NEXT_DESC_PTR = rxbuf[0]->Dma; - } - } - for (i = 0; i < TX_BUF_CNT; i++) { - txbuf[i] = SetupTxBuffer(i); - if (i > 0) { - txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = txbuf[i]->Dma; - if (i == (TX_BUF_CNT - 1)) - txbuf[i]->Dma[1].NEXT_DESC_PTR = txbuf[0]->Dma; - } - } - - /* Set RX DMA */ - bfin_write_DMA1_NEXT_DESC_PTR(rxbuf[0]->Dma); - bfin_write_DMA1_CONFIG(rxbuf[0]->Dma[0].CONFIG_DATA); - - /* Wait MII done */ - bfin_miiphy_wait(); - - /* We enable only RX here */ - /* ASTP : Enable Automatic Pad Stripping - PR : Promiscuous Mode for test - PSF : Receive frames with total length less than 64 bytes. - FDMODE : Full Duplex Mode - LB : Internal Loopback for test - RE : Receiver Enable */ - if (dat == FDMODE) - opmode = ASTP | FDMODE | PSF; - else - opmode = ASTP | PSF; - opmode |= RE; -#ifdef CONFIG_RMII - opmode |= TE | RMII; -#endif - /* Turn on the EMAC */ - bfin_write_EMAC_OPMODE(opmode); - return 0; -} - -static void bfin_EMAC_halt(struct eth_device *dev) -{ - debug("Eth_halt: ......\n"); - /* Turn off the EMAC */ - bfin_write_EMAC_OPMODE(0); - /* Turn off the EMAC RX DMA */ - bfin_write_DMA1_CONFIG(0); - bfin_write_DMA2_CONFIG(0); -} - -ADI_ETHER_BUFFER *SetupRxBuffer(int no) -{ - ADI_ETHER_FRAME_BUFFER *frmbuf; - ADI_ETHER_BUFFER *buf; - int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ - int total_size = nobytes_buffer + RECV_BUFSIZE; - - buf = (void *) (RXBUF_BASE_ADDR + no * total_size); - frmbuf = (void *) (RXBUF_BASE_ADDR + no * total_size + nobytes_buffer); - - memset(buf, 0x00, nobytes_buffer); - buf->FrmData = frmbuf; - memset(frmbuf, 0xfe, RECV_BUFSIZE); - - /* set up first desc to point to receive frame buffer */ - buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]); - buf->Dma[0].START_ADDR = (u32) buf->FrmData; - buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */ - buf->Dma[0].CONFIG.b_WNR = 1; /* Write to memory */ - buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ - buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */ - buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ - - /* set up second desc to point to status word */ - buf->Dma[1].NEXT_DESC_PTR = buf->Dma; - buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum; - buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ - buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ - buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ - buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */ - buf->Dma[1].CONFIG.b_NDSIZE = 5; /* must be 0 when FLOW is 0 */ - buf->Dma[1].CONFIG.b_FLOW = 7; /* stop */ - - return buf; -} - -ADI_ETHER_BUFFER *SetupTxBuffer(int no) -{ - ADI_ETHER_FRAME_BUFFER *frmbuf; - ADI_ETHER_BUFFER *buf; - int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ - int total_size = nobytes_buffer + RECV_BUFSIZE; - - buf = (void *) (TXBUF_BASE_ADDR + no * total_size); - frmbuf = (void *) (TXBUF_BASE_ADDR + no * total_size + nobytes_buffer); - - memset(buf, 0x00, nobytes_buffer); - buf->FrmData = frmbuf; - memset(frmbuf, 0x00, RECV_BUFSIZE); - - /* set up first desc to point to receive frame buffer */ - buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]); - buf->Dma[0].START_ADDR = (u32) buf->FrmData; - buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */ - buf->Dma[0].CONFIG.b_WNR = 0; /* Read to memory */ - buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ - buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */ - buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ - - /* set up second desc to point to status word */ - buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]); - buf->Dma[1].START_ADDR = (u32) & buf->StatusWord; - buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ - buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ - buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ - buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */ - buf->Dma[1].CONFIG.b_NDSIZE = 0; /* must be 0 when FLOW is 0 */ - buf->Dma[1].CONFIG.b_FLOW = 0; /* stop */ - - return buf; -} - -#if defined(CONFIG_POST) && defined(CONFIG_SYS_POST_ETHER) -int ether_post_test(int flags) -{ - uchar buf[64]; - int i, value = 0; - int length; - uint addr; - - printf("\n--------"); - bfin_EMAC_init(NULL, NULL); - /* construct the package */ - addr = bfin_read_EMAC_ADDRLO(); - buf[0] = buf[6] = addr; - buf[1] = buf[7] = addr >> 8; - buf[2] = buf[8] = addr >> 16; - buf[3] = buf[9] = addr >> 24; - addr = bfin_read_EMAC_ADDRHI(); - buf[4] = buf[10] = addr; - buf[5] = buf[11] = addr >> 8; - buf[12] = 0x08; /* Type: ARP */ - buf[13] = 0x06; - buf[14] = 0x00; /* Hardware type: Ethernet */ - buf[15] = 0x01; - buf[16] = 0x08; /* Protocal type: IP */ - buf[17] = 0x00; - buf[18] = 0x06; /* Hardware size */ - buf[19] = 0x04; /* Protocol size */ - buf[20] = 0x00; /* Opcode: request */ - buf[21] = 0x01; - - for (i = 0; i < 42; i++) - buf[i + 22] = i; - printf("--------Send 64 bytes......\n"); - bfin_EMAC_send(NULL, buf, 64); - for (i = 0; i < 100; i++) { - udelay(10000); - if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) { - value = 1; - break; - } - } - if (value == 0) { - printf("--------EMAC can't receive any data\n"); - eth_halt(); - return -1; - } - length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4; - for (i = 0; i < length; i++) { - if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) { - printf("--------EMAC receive error data!\n"); - eth_halt(); - return -1; - } - } - printf("--------receive %d bytes, matched\n", length); - bfin_EMAC_halt(NULL); - return 0; -} -#endif diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h deleted file mode 100644 index 54ffb3830e..0000000000 --- a/drivers/net/bfin_mac.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * bfin_mac.h - some defines/structures for the Blackfin on-chip MAC. - * - * Copyright (c) 2005-2008 Analog Device, Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef __BFIN_MAC_H__ -#define __BFIN_MAC_H__ - -#define RECV_BUFSIZE (0x614) - -typedef struct ADI_DMA_CONFIG_REG { - u16 b_DMA_EN:1; /* 0 Enabled */ - u16 b_WNR:1; /* 1 Direction */ - u16 b_WDSIZE:2; /* 2:3 Transfer word size */ - u16 b_DMA2D:1; /* 4 DMA mode */ - u16 b_RESTART:1; /* 5 Retain FIFO */ - u16 b_DI_SEL:1; /* 6 Data interrupt timing select */ - u16 b_DI_EN:1; /* 7 Data interrupt enabled */ - u16 b_NDSIZE:4; /* 8:11 Flex descriptor size */ - u16 b_FLOW:3; /* 12:14Flow */ -} ADI_DMA_CONFIG_REG; - -typedef struct adi_ether_frame_buffer { - u16 NoBytes; /* the no. of following bytes */ - u8 Dest[6]; /* destination MAC address */ - u8 Srce[6]; /* source MAC address */ - u16 LTfield; /* length/type field */ - u8 Data[0]; /* payload bytes */ -} ADI_ETHER_FRAME_BUFFER; -/* 16 bytes/struct */ - -typedef struct dma_descriptor { - struct dma_descriptor *NEXT_DESC_PTR; - u32 START_ADDR; - union { - u16 CONFIG_DATA; - ADI_DMA_CONFIG_REG CONFIG; - }; -} DMA_DESCRIPTOR; -/* 10 bytes/struct in 12 bytes */ - -typedef struct adi_ether_buffer { - DMA_DESCRIPTOR Dma[2]; /* first for the frame, second for the status */ - ADI_ETHER_FRAME_BUFFER *FrmData;/* pointer to data */ - struct adi_ether_buffer *pNext; /* next buffer */ - struct adi_ether_buffer *pPrev; /* prev buffer */ - u16 IPHdrChksum; /* the IP header checksum */ - u16 IPPayloadChksum; /* the IP header and payload checksum */ - volatile u32 StatusWord; /* the frame status word */ -} ADI_ETHER_BUFFER; -/* 40 bytes/struct in 44 bytes */ - -static ADI_ETHER_BUFFER *SetupRxBuffer(int no); -static ADI_ETHER_BUFFER *SetupTxBuffer(int no); - -static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd); -static void bfin_EMAC_halt(struct eth_device *dev); -static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length); -static int bfin_EMAC_recv(struct eth_device *dev); -static int bfin_EMAC_setup_addr(struct eth_device *dev); - -#endif diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile index fa96bad902..fc7a6da03b 100644 --- a/drivers/net/fm/Makefile +++ b/drivers/net/fm/Makefile @@ -34,5 +34,5 @@ obj-$(CONFIG_ARCH_T4240) += t4240.o obj-$(CONFIG_ARCH_T4160) += t4240.o obj-$(CONFIG_ARCH_B4420) += b4860.o obj-$(CONFIG_ARCH_B4860) += b4860.o -obj-$(CONFIG_LS1043A) += ls1043.o +obj-$(CONFIG_ARCH_LS1043A) += ls1043.o obj-$(CONFIG_ARCH_LS1046A) += ls1046.o diff --git a/drivers/net/ldpaa_eth/Makefile b/drivers/net/ldpaa_eth/Makefile index 5587aa618d..08675ec641 100644 --- a/drivers/net/ldpaa_eth/Makefile +++ b/drivers/net/ldpaa_eth/Makefile @@ -6,4 +6,4 @@ obj-y += ldpaa_wriop.o obj-y += ldpaa_eth.o -obj-$(CONFIG_LS2080A) += ls2080a.o +obj-$(CONFIG_ARCH_LS2080A) += ls2080a.o diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 355aeae854..f6616c5329 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -105,7 +105,7 @@ config SPL_PINCONF if PINCTRL || SPL_PINCTRL -config AR933X_PINCTRL +config PINCTRL_AR933X bool "QCA/Athores ar933x pin control driver" depends on DM && SOC_AR933X help @@ -114,98 +114,118 @@ config AR933X_PINCTRL both the GPIO definitions and pin control functions for each available multiplex function. -config QCA953X_PINCTRL +config PINCTRL_AT91 + bool "AT91 pinctrl driver" + depends on DM + help + This option is to enable the AT91 pinctrl driver for AT91 PIO + controller. + + AT91 PIO controller is a combined gpio-controller, pin-mux and + pin-config module. Each I/O pin may be dedicated as a general-purpose + I/O or be assigned to a function of an embedded peripheral. Each I/O + pin has a glitch filter providing rejection of glitches lower than + one-half of peripheral clock cycle and a debouncing filter providing + rejection of unwanted pulses from key or push button operations. You + can also control the multi-driver capability, pull-up and pull-down + feature on each I/O pin. + +config PINCTRL_AT91PIO4 + bool "AT91 PIO4 pinctrl driver" + depends on DM + help + This option is to enable the AT91 pinctrl driver for AT91 PIO4 + controller which is available on SAMA5D2 SoC. + +config PINCTRL_PIC32 + bool "Microchip PIC32 pin-control and pin-mux driver" + depends on DM && MACH_PIC32 + default y + help + Supports individual pin selection and configuration for each + remappable peripheral available on Microchip PIC32 + SoCs. This driver is controlled by a device tree node which + contains both GPIO defintion and pin control functions. + +config PINCTRL_QCA953X bool "QCA/Athores qca953x pin control driver" depends on DM && SOC_QCA953X help Support pin multiplexing control on QCA/Athores qca953x SoCs. - The driver is controlled by a device tree node which contains - both the GPIO definitions and pin control functions for each - available multiplex function. -config ROCKCHIP_RK3036_PINCTRL + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + +config PINCTRL_ROCKCHIP_RK3036 bool "Rockchip rk3036 pin control driver" depends on DM help - Support pin multiplexing control on Rockchip rk3036 SoCs. The driver is - controlled by a device tree node which contains both the GPIO - definitions and pin control functions for each available multiplex - function. + Support pin multiplexing control on Rockchip rk3036 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. -config ROCKCHIP_RK3188_PINCTRL +config PINCTRL_ROCKCHIP_RK3188 bool "Rockchip rk3188 pin control driver" depends on DM help - Support pin multiplexing control on Rockchip rk3188 SoCs. The driver - is controlled by a device tree node which contains both the GPIO - definitions and pin control functions for each available multiplex - function. + Support pin multiplexing control on Rockchip rk3188 SoCs. -config ROCKCHIP_RK3288_PINCTRL - bool "Rockchip rk3288 pin control driver" - depends on DM - help - Support pin multiplexing control on Rockchip rk3288 SoCs. The driver - is controlled by a device tree node which contains both the GPIO - definitions and pin control functions for each available multiplex - function. + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. -config PINCTRL_AT91 - bool "AT91 pinctrl driver" +config PINCTRL_ROCKCHIP_RK3288 + bool "Rockchip rk3288 pin control driver" depends on DM help - This option is to enable the AT91 pinctrl driver for AT91 PIO - controller. AT91 PIO controller is a combined gpio-controller, - pin-mux and pin-config module. Each I/O pin may be dedicated as - a general-purpose I/O or be assigned to a function of an embedded - peripheral. Each I/O pin has a glitch filter providing rejection of - glitches lower than one-half of peripheral clock cycle and - a debouncing filter providing rejection of unwanted pulses from key - or push button operations. You can also control the multi-driver - capability, pull-up and pull-down feature on each I/O pin. + Support pin multiplexing control on Rockchip rk3288 SoCs. -config PINCTRL_AT91PIO4 - bool "AT91 PIO4 pinctrl driver" - depends on DM - help - This option is to enable the AT91 pinctrl driver for AT91 PIO4 - controller which is available on SAMA5D2 SoC. + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. -config ROCKCHIP_RK3328_PINCTRL +config PINCTRL_ROCKCHIP_RK3328 bool "Rockchip rk3328 pin control driver" depends on DM help - Support pin multiplexing control on Rockchip rk3328 SoCs. The driver - is controlled by a device tree node which contains both the GPIO - definitions and pin control functions for each available multiplex - function. + Support pin multiplexing control on Rockchip rk3328 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. -config ROCKCHIP_RK3399_PINCTRL +config PINCTRL_ROCKCHIP_RK3399 bool "Rockchip rk3399 pin control driver" depends on DM help - Support pin multiplexing control on Rockchip rk3399 SoCs. The driver - is controlled by a device tree node which contains both the GPIO - definitions and pin control functions for each available multiplex - function. + Support pin multiplexing control on Rockchip rk3399 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. config PINCTRL_SANDBOX bool "Sandbox pinctrl driver" depends on SANDBOX help - This enables pinctrl driver for sandbox. Currently, this driver - actually does nothing but print debug messages when pinctrl - operations are invoked. + This enables pinctrl driver for sandbox. -config PIC32_PINCTRL - bool "Microchip PIC32 pin-control and pin-mux driver" - depends on DM && MACH_PIC32 - default y + Currently, this driver actually does nothing but print debug + messages when pinctrl operations are invoked. + +config PINCTRL_SINGLE + bool "Single register pin-control and pin-multiplex driver" + depends on DM help - Supports individual pin selection and configuration for each remappable - peripheral available on Microchip PIC32 SoCs. This driver is controlled - by a device tree node which contains both GPIO defintion and pin control - functions. + This enables pinctrl driver for systems using a single register for + pin configuration and multiplexing. TI's AM335X SoCs are examples of + such systems. + + Depending on the platform make sure to also enable OF_TRANSLATE and + eventually SPL_OF_TRANSLATE to get correct address translations. config PINCTRL_STI bool "STMicroelectronics STi pin-control and pin-mux driver" @@ -213,28 +233,29 @@ config PINCTRL_STI default y help Support pin multiplexing control on STMicrolectronics STi SoCs. + The driver is controlled by a device tree node which contains both - the GPIO definitions and pin control functions for each available multiplex - function. + the GPIO definitions and pin control functions for each available + multiplex function. config PINCTRL_STM32 bool "ST STM32 pin control driver" depends on DM help - Supports pin multiplexing control on stm32 SoCs. The driver is - controlled by a device tree node which contains both the GPIO - definitions and pin control functions for each available multiplex - function. + Supports pin multiplexing control on stm32 SoCs. -config PINCTRL_SINGLE - bool "Single register pin-control and pin-multiplex driver" - depends on DM - help - This enables pinctrl driver for systems using a single register for - pin configuration and multiplexing. TI's AM335X SoCs are examples of - such systems. - Depending on the platform make sure to also enable OF_TRANSLATE and - eventually SPL_OF_TRANSLATE to get correct address translations. + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + +config ASPEED_AST2500_PINCTRL + bool "Aspeed AST2500 pin control driver" + depends on DM && PINCTRL_GENERIC && ASPEED_AST2500 + default y + help + Support pin multiplexing control on Aspeed ast2500 SoC. The driver uses + Generic Pinctrl framework and is compatible with the Linux driver, + i.e. it uses the same device tree configuration. endif diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index bbb2480e86..1e5c4257c4 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -8,12 +8,13 @@ obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-y += nxp/ +obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-$(CONFIG_ARCH_ATH79) += ath79/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ -obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o +obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/ diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile new file mode 100644 index 0000000000..2e6ed604c8 --- /dev/null +++ b/drivers/pinctrl/aspeed/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ASPEED_AST2500_PINCTRL) += pinctrl_ast2500.o diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2500.c b/drivers/pinctrl/aspeed/pinctrl_ast2500.c new file mode 100644 index 0000000000..01f97c1b48 --- /dev/null +++ b/drivers/pinctrl/aspeed/pinctrl_ast2500.c @@ -0,0 +1,127 @@ +/* + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/pinctrl.h> +#include <asm/arch/scu_ast2500.h> +#include <dm/pinctrl.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * This driver works with very simple configuration that has the same name + * for group and function. This way it is compatible with the Linux Kernel + * driver. + */ + +struct ast2500_pinctrl_priv { + struct ast2500_scu *scu; +}; + +static int ast2500_pinctrl_probe(struct udevice *dev) +{ + struct ast2500_pinctrl_priv *priv = dev_get_priv(dev); + + priv->scu = ast_get_scu(); + + return 0; +} + +struct ast2500_group_config { + char *group_name; + /* Control register number (1-10) */ + unsigned reg_num; + /* The mask of control bits in the register */ + u32 ctrl_bit_mask; +}; + +static const struct ast2500_group_config ast2500_groups[] = { + { "I2C1", 8, (1 << 13) | (1 << 12) }, + { "I2C2", 8, (1 << 15) | (1 << 14) }, + { "I2C3", 8, (1 << 16) }, + { "I2C4", 5, (1 << 17) }, + { "I2C4", 5, (1 << 17) }, + { "I2C5", 5, (1 << 18) }, + { "I2C6", 5, (1 << 19) }, + { "I2C7", 5, (1 << 20) }, + { "I2C8", 5, (1 << 21) }, + { "I2C9", 5, (1 << 22) }, + { "I2C10", 5, (1 << 23) }, + { "I2C11", 5, (1 << 24) }, + { "I2C12", 5, (1 << 25) }, + { "I2C13", 5, (1 << 26) }, + { "I2C14", 5, (1 << 27) }, + { "MAC1LINK", 1, (1 << 0) }, + { "MDIO1", 3, (1 << 31) | (1 << 30) }, + { "MAC2LINK", 1, (1 << 1) }, + { "MDIO2", 5, (1 << 2) }, +}; + +static int ast2500_pinctrl_get_groups_count(struct udevice *dev) +{ + debug("PINCTRL: get_(functions/groups)_count\n"); + + return ARRAY_SIZE(ast2500_groups); +} + +static const char *ast2500_pinctrl_get_group_name(struct udevice *dev, + unsigned selector) +{ + debug("PINCTRL: get_(function/group)_name %u\n", selector); + + return ast2500_groups[selector].group_name; +} + +static int ast2500_pinctrl_group_set(struct udevice *dev, unsigned selector, + unsigned func_selector) +{ + struct ast2500_pinctrl_priv *priv = dev_get_priv(dev); + const struct ast2500_group_config *config; + u32 *ctrl_reg; + + debug("PINCTRL: group_set <%u, %u>\n", selector, func_selector); + if (selector >= ARRAY_SIZE(ast2500_groups)) + return -EINVAL; + + config = &ast2500_groups[selector]; + if (config->reg_num > 6) + ctrl_reg = &priv->scu->pinmux_ctrl1[config->reg_num - 7]; + else + ctrl_reg = &priv->scu->pinmux_ctrl[config->reg_num - 1]; + + ast_scu_unlock(priv->scu); + setbits_le32(ctrl_reg, config->ctrl_bit_mask); + ast_scu_lock(priv->scu); + + return 0; +} + +static struct pinctrl_ops ast2500_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, + .get_groups_count = ast2500_pinctrl_get_groups_count, + .get_group_name = ast2500_pinctrl_get_group_name, + .get_functions_count = ast2500_pinctrl_get_groups_count, + .get_function_name = ast2500_pinctrl_get_group_name, + .pinmux_group_set = ast2500_pinctrl_group_set, +}; + +static const struct udevice_id ast2500_pinctrl_ids[] = { + { .compatible = "aspeed,ast2500-pinctrl" }, + { .compatible = "aspeed,g5-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_ast2500) = { + .name = "aspeed_ast2500_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = ast2500_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct ast2500_pinctrl_priv), + .ops = &ast2500_pinctrl_ops, + .probe = ast2500_pinctrl_probe, +}; diff --git a/drivers/pinctrl/ath79/Makefile b/drivers/pinctrl/ath79/Makefile index dcea10ace6..c87a9aa3e7 100644 --- a/drivers/pinctrl/ath79/Makefile +++ b/drivers/pinctrl/ath79/Makefile @@ -2,5 +2,5 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_AR933X_PINCTRL) += pinctrl_ar933x.o -obj-$(CONFIG_QCA953x_PINCTRL) += pinctrl_qca953x.o +obj-$(CONFIG_PINCTRL_AR933X) += pinctrl_ar933x.o +obj-$(CONFIG_PINCTRL_QCA953x) += pinctrl_qca953x.o diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index aa2c440b14..d7b5ea3e1c 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,10 +1,46 @@ #include <common.h> -#include <asm/arch/gpio.h> #include <dm.h> #include <dm/pinctrl.h> +#include <asm/arch/gpio.h> +#include <asm/gpio.h> +#include <asm/io.h> DECLARE_GLOBAL_DATA_PTR; +#define MAX_PINS_ONE_IP 70 +#define MODE_BITS_MASK 3 +#define OSPEED_MASK 3 +#define PUPD_MASK 3 +#define OTYPE_MSK 1 +#define AFR_MASK 0xF + +static int stm32_gpio_config(struct gpio_desc *desc, + const struct stm32_gpio_ctl *ctl) +{ + struct stm32_gpio_priv *priv = dev_get_priv(desc->dev); + struct stm32_gpio_regs *regs = priv->regs; + u32 index; + + if (!ctl || ctl->af > 15 || ctl->mode > 3 || ctl->otype > 1 || + ctl->pupd > 2 || ctl->speed > 3) + return -EINVAL; + + index = (desc->offset & 0x07) * 4; + clrsetbits_le32(®s->afr[desc->offset >> 3], AFR_MASK << index, + ctl->af << index); + + index = desc->offset * 2; + clrsetbits_le32(®s->moder, MODE_BITS_MASK << index, + ctl->mode << index); + clrsetbits_le32(®s->ospeedr, OSPEED_MASK << index, + ctl->speed << index); + clrsetbits_le32(®s->pupdr, PUPD_MASK << index, ctl->pupd << index); + + index = desc->offset; + clrsetbits_le32(®s->otyper, OTYPE_MSK << index, ctl->otype << index); + + return 0; +} static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin) { gpio_dsc->port = (port_pin & 0xF000) >> 12; @@ -18,6 +54,7 @@ static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin) static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) { gpio_fn &= 0x00FF; + gpio_ctl->af = 0; switch (gpio_fn) { case 0: @@ -59,7 +96,7 @@ static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node) static int stm32_pinctrl_set_state_simple(struct udevice *dev, struct udevice *periph) { - u32 pin_mux[50]; + u32 pin_mux[MAX_PINS_ONE_IP]; struct fdtdec_phandle_args args; int rv, len; @@ -85,11 +122,16 @@ static int stm32_pinctrl_set_state_simple(struct udevice *dev, if (len < 0) return -EINVAL; for (i = 0; i < len; i++) { + struct gpio_desc desc; debug("%s: pinmux = %x\n", __func__, *(pin_mux + i)); prep_gpio_dsc(&gpio_dsc, *(pin_mux + i)); prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), args.node); - - rv = stm32_gpio_config(&gpio_dsc, &gpio_ctl); + rv = uclass_get_device_by_seq(UCLASS_GPIO, + gpio_dsc.port, &desc.dev); + if (rv) + return rv; + desc.offset = gpio_dsc.pin; + rv = stm32_gpio_config(&desc, &gpio_ctl); debug("%s: rv = %d\n\n", __func__, rv); if (rv) return rv; diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index b0b698ac04..69eef4c024 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -5,8 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_ROCKCHIP_RK3036_PINCTRL) += pinctrl_rk3036.o -obj-$(CONFIG_ROCKCHIP_RK3188_PINCTRL) += pinctrl_rk3188.o -obj-$(CONFIG_ROCKCHIP_RK3288_PINCTRL) += pinctrl_rk3288.o -obj-$(CONFIG_ROCKCHIP_RK3328_PINCTRL) += pinctrl_rk3328.o -obj-$(CONFIG_ROCKCHIP_RK3399_PINCTRL) += pinctrl_rk3399.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3036) += pinctrl_rk3036.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3188) += pinctrl_rk3188.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3288) += pinctrl_rk3288.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3328) += pinctrl_rk3328.o +obj-$(CONFIG_PINCTRL_ROCKCHIP_RK3399) += pinctrl_rk3399.o diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 64e5bc2f74..911ecb1144 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -10,7 +10,7 @@ choice prompt "Select Sunxi PMIC Variant" depends on ARCH_SUNXI default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I - default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 + default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40 default AXP818_POWER if MACH_SUN8I_A83T default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5 || MACH_SUN50I @@ -37,7 +37,7 @@ config AXP209_POWER config AXP221_POWER bool "axp221 / axp223 pmic support" - depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 + depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40 select CMD_POWEROFF ---help--- Select this to enable support for the axp221/axp223 pmic found on most @@ -70,7 +70,7 @@ endchoice config AXP_DCDC1_VOLT int "axp pmic dcdc1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER - default 3300 if AXP818_POWER + default 3300 if AXP818_POWER || MACH_SUN8I_R40 default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I ---help--- Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to @@ -97,6 +97,7 @@ config AXP_DCDC2_VOLT On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V. On A80 boards dcdc2 powers the GPU and can be left off. On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V. + On R40 boards dcdc2 is VDD-CPU and should be 1.1V config AXP_DCDC3_VOLT int "axp pmic dcdc3 voltage" @@ -104,6 +105,7 @@ config AXP_DCDC3_VOLT default 900 if AXP809_POWER || AXP818_POWER default 1500 if AXP152_POWER default 1250 if AXP209_POWER + default 1100 if MACH_SUN8I_R40 default 1200 if MACH_SUN6I || MACH_SUN8I ---help--- Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to @@ -114,6 +116,7 @@ config AXP_DCDC3_VOLT On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V. On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V. On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V. + On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V. config AXP_DCDC4_VOLT int "axp pmic dcdc4 voltage" @@ -138,13 +141,13 @@ config AXP_DCDC5_VOLT ---help--- Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to disable dcdc5. - On A23 / A31 / A33 / A80 / A83T boards dcdc5 is VCC-DRAM and + On A23 / A31 / A33 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and should be 1.5V, 1.35V if DDR3L is used. config AXP_ALDO1_VOLT int "axp pmic (a)ldo1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER - default 0 if MACH_SUN6I + default 0 if MACH_SUN6I || MACH_SUN8I_R40 default 1800 if MACH_SUN8I_A83T default 3000 if MACH_SUN8I || MACH_SUN9I ---help--- @@ -183,7 +186,8 @@ config AXP_ALDO3_VOLT Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to disable aldo3. On A10(s) / A13 / A20 boards aldo3 should be 2.8V. - On A23 / A31 / A33 boards aldo3 is VCC-PLL and AVCC and should be 3.0V. + On A23 / A31 / A33 / R40 boards aldo3 is VCC-PLL and AVCC and should + be 3.0V. On A80 boards aldo3 is normally not used. On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be 3.0V. diff --git a/drivers/power/Makefile b/drivers/power/Makefile index b43523e628..90a3b00a7c 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -5,7 +5,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_AS3722_POWER) += as3722.o obj-$(CONFIG_AXP152_POWER) += axp152.o obj-$(CONFIG_AXP209_POWER) += axp209.o obj-$(CONFIG_AXP221_POWER) += axp221.o diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 03fea078da..4891b1704e 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -40,6 +40,14 @@ config PMIC_ACT8846 functions. It uses an I2C interface and is designed for use with tablets and smartphones. +config PMIC_AS3722 + bool "Enable support for the Austria Micro Systems (AMS) AS7322 PMIC" + help + The AS3722 includes 7 DC/DC buck convertors, 11 low-noise LDOs, a + real-time clock, GPIOs, ADC and a few other features. It uses an I2C + interface and is designs to cover most of the power managementment + required for a tablets or laptop. + config DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 40240c7936..5f1bef33cd 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o +obj-$(CONFIG_PMIC_AS3722) += as3722.o obj-$(CONFIG_PMIC_MAX8997) += max8997.o obj-$(CONFIG_PMIC_PM8916) += pm8916.o obj-$(CONFIG_PMIC_RK808) += rk808.o diff --git a/drivers/power/as3722.c b/drivers/power/pmic/as3722.c index c09e1de06f..c09e1de06f 100644 --- a/drivers/power/as3722.c +++ b/drivers/power/pmic/as3722.c diff --git a/drivers/power/sy8106a.c b/drivers/power/sy8106a.c index bbf116f655..f9db3965f2 100644 --- a/drivers/power/sy8106a.c +++ b/drivers/power/sy8106a.c @@ -12,6 +12,7 @@ #define SY8106A_VOUT1_SEL 1 #define SY8106A_VOUT1_SEL_ENABLE (1 << 7) +#ifdef CONFIG_SPL_BUILD static u8 sy8106a_mvolt_to_cfg(int mvolt, int min, int max, int div) { if (mvolt < min) @@ -27,3 +28,4 @@ int sy8106a_set_vout1(unsigned int mvolt) u8 data = sy8106a_mvolt_to_cfg(mvolt, 680, 1950, 10) | SY8106A_VOUT1_SEL_ENABLE; return i2c_write(SY8106A_I2C_ADDR, SY8106A_VOUT1_SEL, 1, &data, 1); } +#endif diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 37ea2b88ea..e827558052 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -27,6 +27,14 @@ config PWM_ROCKCHIP Various options provided in the hardware (such as capture mode and continuous/single-shot) are not supported by the driver. +config PWM_SANDBOX + bool "Enable support for the sandbox PWM" + help + This is a sandbox PWM used for testing. It provides 3 channels and + records the settings passed into it, but otherwise does nothing + useful. The PWM can be enabled but is not connected to any outputs + so this is not very useful. + config PWM_TEGRA bool "Enable support for the Tegra PWM" depends on DM_PWM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index b037130385..29d59916cb 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o +obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o diff --git a/drivers/pwm/sandbox_pwm.c b/drivers/pwm/sandbox_pwm.c new file mode 100644 index 0000000000..c2ce974dde --- /dev/null +++ b/drivers/pwm/sandbox_pwm.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <pwm.h> +#include <asm/test.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + NUM_CHANNELS = 3, +}; + +struct sandbox_pwm_chan { + uint period_ns; + uint duty_ns; + bool enable; +}; + +struct sandbox_pwm_priv { + struct sandbox_pwm_chan chan[NUM_CHANNELS]; +}; + +static int sandbox_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct sandbox_pwm_priv *priv = dev_get_priv(dev); + struct sandbox_pwm_chan *chan; + + if (channel >= NUM_CHANNELS) + return -ENOSPC; + chan = &priv->chan[channel]; + chan->period_ns = period_ns; + chan->duty_ns = duty_ns; + + return 0; +} + +static int sandbox_pwm_set_enable(struct udevice *dev, uint channel, + bool enable) +{ + struct sandbox_pwm_priv *priv = dev_get_priv(dev); + struct sandbox_pwm_chan *chan; + + if (channel >= NUM_CHANNELS) + return -ENOSPC; + chan = &priv->chan[channel]; + chan->enable = enable; + + return 0; +} + +static const struct pwm_ops sandbox_pwm_ops = { + .set_config = sandbox_pwm_set_config, + .set_enable = sandbox_pwm_set_enable, +}; + +static const struct udevice_id sandbox_pwm_ids[] = { + { .compatible = "sandbox,pwm" }, + { } +}; + +U_BOOT_DRIVER(warm_pwm_sandbox) = { + .name = "pwm_sandbox", + .id = UCLASS_PWM, + .of_match = sandbox_pwm_ids, + .ops = &sandbox_pwm_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_pwm_priv), +}; diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 4231594776..4f0a27892f 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -13,7 +13,7 @@ #include <asm/io.h> #include <linux/immap_qe.h> #include <fsl_qe.h> -#ifdef CONFIG_LS102XA +#ifdef CONFIG_ARCH_LS1021A #include <asm/arch/immap_ls102xa.h> #endif @@ -355,7 +355,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) size_t length; const struct qe_header *hdr; #ifdef CONFIG_DEEP_SLEEP -#ifdef CONFIG_LS102XA +#ifdef CONFIG_ARCH_LS1021A struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; #else ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -494,7 +494,7 @@ int u_qe_upload_firmware(const struct qe_firmware *firmware) size_t length; const struct qe_header *hdr; #ifdef CONFIG_DEEP_SLEEP -#ifdef CONFIG_LS102XA +#ifdef CONFIG_ARCH_LS1021A struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; #else ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index ff09f226df..61afd7a92a 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -16,3 +16,11 @@ config SPL_RAM If this is acceptable and you have a need to use RAM drivers in SPL, enable this option. It might provide a cleaner interface to setting up RAM (e.g. SDRAM / DDR) within SPL. + +config STM32_SDRAM + bool "Enable STM32 SDRAM support" + depends on RAM + help + STM32F7 family devices support flexible memory controller(FMC) to + support external memories like sdram, psram & nand. + This driver is for the sdram memory interface with the FMC. diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index 0e102491a4..ecb036dfba 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -6,3 +6,4 @@ # obj-$(CONFIG_RAM) += ram-uclass.o obj-$(CONFIG_SANDBOX) += sandbox_ram.o +obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o diff --git a/drivers/ram/stm32_sdram.c b/drivers/ram/stm32_sdram.c new file mode 100644 index 0000000000..48b4979e62 --- /dev/null +++ b/drivers/ram/stm32_sdram.c @@ -0,0 +1,179 @@ +/* + * (C) Copyright 2017 + * Vikas Manocha, <vikas.manocha@st.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <ram.h> +#include <asm/io.h> +#include <asm/arch/fmc.h> +#include <asm/arch/stm32.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct stm32_sdram_control { + u8 no_columns; + u8 no_rows; + u8 memory_width; + u8 no_banks; + u8 cas_latency; + u8 sdclk; + u8 rd_burst; + u8 rd_pipe_delay; +}; + +struct stm32_sdram_timing { + u8 tmrd; + u8 txsr; + u8 tras; + u8 trc; + u8 trp; + u8 twr; + u8 trcd; +}; +struct stm32_sdram_params { + u8 no_sdram_banks; + struct stm32_sdram_control sdram_control; + struct stm32_sdram_timing sdram_timing; + u32 sdram_ref_count; +}; + +#define SDRAM_MODE_BL_SHIFT 0 +#define SDRAM_MODE_CAS_SHIFT 4 +#define SDRAM_MODE_BL 0 + +int stm32_sdram_init(struct udevice *dev) +{ + struct stm32_sdram_params *params = dev_get_platdata(dev); + + writel(params->sdram_control.sdclk << FMC_SDCR_SDCLK_SHIFT + | params->sdram_control.cas_latency << FMC_SDCR_CAS_SHIFT + | params->sdram_control.no_banks << FMC_SDCR_NB_SHIFT + | params->sdram_control.memory_width << FMC_SDCR_MWID_SHIFT + | params->sdram_control.no_rows << FMC_SDCR_NR_SHIFT + | params->sdram_control.no_columns << FMC_SDCR_NC_SHIFT + | params->sdram_control.rd_pipe_delay << FMC_SDCR_RPIPE_SHIFT + | params->sdram_control.rd_burst << FMC_SDCR_RBURST_SHIFT, + &STM32_SDRAM_FMC->sdcr1); + + writel(params->sdram_timing.trcd << FMC_SDTR_TRCD_SHIFT + | params->sdram_timing.trp << FMC_SDTR_TRP_SHIFT + | params->sdram_timing.twr << FMC_SDTR_TWR_SHIFT + | params->sdram_timing.trc << FMC_SDTR_TRC_SHIFT + | params->sdram_timing.tras << FMC_SDTR_TRAS_SHIFT + | params->sdram_timing.txsr << FMC_SDTR_TXSR_SHIFT + | params->sdram_timing.tmrd << FMC_SDTR_TMRD_SHIFT, + &STM32_SDRAM_FMC->sdtr1); + + writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_START_CLOCK, + &STM32_SDRAM_FMC->sdcmr); + udelay(200); /* 200 us delay, page 10, "Power-Up" */ + FMC_BUSY_WAIT(); + + writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_PRECHARGE, + &STM32_SDRAM_FMC->sdcmr); + udelay(100); + FMC_BUSY_WAIT(); + + writel((FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_AUTOREFRESH + | 7 << FMC_SDCMR_NRFS_SHIFT), &STM32_SDRAM_FMC->sdcmr); + udelay(100); + FMC_BUSY_WAIT(); + + writel(FMC_SDCMR_BANK_1 | (SDRAM_MODE_BL << SDRAM_MODE_BL_SHIFT + | params->sdram_control.cas_latency << SDRAM_MODE_CAS_SHIFT) + << FMC_SDCMR_MODE_REGISTER_SHIFT | FMC_SDCMR_MODE_WRITE_MODE, + &STM32_SDRAM_FMC->sdcmr); + udelay(100); + FMC_BUSY_WAIT(); + + writel(FMC_SDCMR_BANK_1 | FMC_SDCMR_MODE_NORMAL, + &STM32_SDRAM_FMC->sdcmr); + FMC_BUSY_WAIT(); + + /* Refresh timer */ + writel((params->sdram_ref_count) << 1, &STM32_SDRAM_FMC->sdrtr); + + return 0; +} + +static int stm32_fmc_ofdata_to_platdata(struct udevice *dev) +{ + int ret; + int node = dev->of_offset; + const void *blob = gd->fdt_blob; + struct stm32_sdram_params *params = dev_get_platdata(dev); + + params->no_sdram_banks = fdtdec_get_uint(blob, node, "mr-nbanks", 1); + debug("%s, no of banks = %d\n", __func__, params->no_sdram_banks); + + fdt_for_each_subnode(node, blob, node) { + ret = fdtdec_get_byte_array(blob, node, "st,sdram-control", + (u8 *)¶ms->sdram_control, + sizeof(params->sdram_control)); + if (ret) + return ret; + ret = fdtdec_get_byte_array(blob, node, "st,sdram-timing", + (u8 *)¶ms->sdram_timing, + sizeof(params->sdram_timing)); + if (ret) + return ret; + + params->sdram_ref_count = fdtdec_get_int(blob, node, + "st,sdram-refcount", 8196); + } + + return 0; +} + +static int stm32_fmc_probe(struct udevice *dev) +{ +#ifdef CONFIG_CLK + int ret; + struct clk clk; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } +#endif + ret = stm32_sdram_init(dev); + if (ret) + return ret; + + return 0; +} + +static int stm32_fmc_get_info(struct udevice *dev, struct ram_info *info) +{ + return 0; +} + +static struct ram_ops stm32_fmc_ops = { + .get_info = stm32_fmc_get_info, +}; + +static const struct udevice_id stm32_fmc_ids[] = { + { .compatible = "st,stm32-fmc" }, + { } +}; + +U_BOOT_DRIVER(stm32_fmc) = { + .name = "stm32_fmc", + .id = UCLASS_RAM, + .of_match = stm32_fmc_ids, + .ops = &stm32_fmc_ops, + .ofdata_to_platdata = stm32_fmc_ofdata_to_platdata, + .probe = stm32_fmc_probe, + .platdata_auto_alloc_size = sizeof(struct stm32_sdram_params), +}; diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index fa77ee4ada..80f4646a79 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -51,4 +51,14 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block. +config AST2500_RESET + bool "Reset controller driver for AST2500 SoCs" + depends on DM_RESET && WDT_ASPEED + default y if ASPEED_AST2500 + help + Support for reset controller on AST2500 SoC. This controller uses + watchdog to reset different peripherals and thus only supports + resets that are supported by watchdog. The main limitation though + is that some reset signals, like I2C or MISC reset multiple devices. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 2b963961d6..630b4b4e54 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_STI_RESET) += sti-reset.o obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o +obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o diff --git a/drivers/reset/ast2500-reset.c b/drivers/reset/ast2500-reset.c new file mode 100644 index 0000000000..b2c89e1f1e --- /dev/null +++ b/drivers/reset/ast2500-reset.c @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <misc.h> +#include <reset.h> +#include <reset-uclass.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/scu_ast2500.h> +#include <asm/arch/wdt.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct ast2500_reset_priv { + /* WDT used to perform resets. */ + struct udevice *wdt; + struct ast2500_scu *scu; +}; + +static int ast2500_ofdata_to_platdata(struct udevice *dev) +{ + struct ast2500_reset_priv *priv = dev_get_priv(dev); + int ret; + + ret = uclass_get_device_by_phandle(UCLASS_WDT, dev, "aspeed,wdt", + &priv->wdt); + if (ret) { + debug("%s: can't find WDT for reset controller", __func__); + return ret; + } + + return 0; +} + +static int ast2500_reset_assert(struct reset_ctl *reset_ctl) +{ + struct ast2500_reset_priv *priv = dev_get_priv(reset_ctl->dev); + u32 reset_mode, reset_mask; + bool reset_sdram; + int ret; + + /* + * To reset SDRAM, a specifal flag in SYSRESET register + * needs to be enabled first + */ + reset_mode = ast_reset_mode_from_flags(reset_ctl->id); + reset_mask = ast_reset_mask_from_flags(reset_ctl->id); + reset_sdram = reset_mode == WDT_CTRL_RESET_SOC && + (reset_mask & WDT_RESET_SDRAM); + + if (reset_sdram) { + ast_scu_unlock(priv->scu); + setbits_le32(&priv->scu->sysreset_ctrl1, + SCU_SYSRESET_SDRAM_WDT); + ret = wdt_expire_now(priv->wdt, reset_ctl->id); + clrbits_le32(&priv->scu->sysreset_ctrl1, + SCU_SYSRESET_SDRAM_WDT); + ast_scu_lock(priv->scu); + } else { + ret = wdt_expire_now(priv->wdt, reset_ctl->id); + } + + return ret; +} + +static int ast2500_reset_request(struct reset_ctl *reset_ctl) +{ + debug("%s(reset_ctl=%p) (dev=%p, id=%lu)\n", __func__, reset_ctl, + reset_ctl->dev, reset_ctl->id); + + return 0; +} + +static int ast2500_reset_probe(struct udevice *dev) +{ + struct ast2500_reset_priv *priv = dev_get_priv(dev); + + priv->scu = ast_get_scu(); + + return 0; +} + +static const struct udevice_id ast2500_reset_ids[] = { + { .compatible = "aspeed,ast2500-reset" }, + { } +}; + +struct reset_ops ast2500_reset_ops = { + .rst_assert = ast2500_reset_assert, + .request = ast2500_reset_request, +}; + +U_BOOT_DRIVER(ast2500_reset) = { + .name = "ast2500_reset", + .id = UCLASS_RESET, + .of_match = ast2500_reset_ids, + .probe = ast2500_reset_probe, + .ops = &ast2500_reset_ops, + .ofdata_to_platdata = ast2500_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct ast2500_reset_priv), +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cb79a01631..d06130c7a2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -23,4 +23,11 @@ config RTC_PCF2127 has a selectable I2C-bus or SPI-bus, a backup battery switch-over circuit, a programmable watchdog function, a timestamp function, and many other features. +config RTC_DS1307 + bool "Enable DS1307 driver" + depends on DM_RTC + help + Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and + compatible Real Time Clock devices. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c919427085..87c3d9cae2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_DM_RTC) += rtc-uclass.o obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o -obj-$(CONFIG_RTC_BFIN) += bfin_rtc.o obj-y += date.o obj-$(CONFIG_RTC_DAVINCI) += davinci.o obj-$(CONFIG_RTC_DS1302) += ds1302.o diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c deleted file mode 100644 index a079a1d472..0000000000 --- a/drivers/rtc/bfin_rtc.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2004-2008 Analog Devices Inc. - * - * (C) Copyright 2001 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <command.h> -#include <rtc.h> - -#if defined(CONFIG_CMD_DATE) - -#include <asm/blackfin.h> -#include <asm/mach-common/bits/rtc.h> - -#define pr_stamp() debug("%s:%s:%i: here i am\n", __FILE__, __func__, __LINE__) - -#define MIN_TO_SECS(x) (60 * (x)) -#define HRS_TO_SECS(x) (60 * MIN_TO_SECS(x)) -#define DAYS_TO_SECS(x) (24 * HRS_TO_SECS(x)) - -#define NUM_SECS_IN_MIN MIN_TO_SECS(1) -#define NUM_SECS_IN_HR HRS_TO_SECS(1) -#define NUM_SECS_IN_DAY DAYS_TO_SECS(1) - -/* Enable the RTC prescaler enable register */ -void rtc_init(void) -{ - if (!(bfin_read_RTC_PREN() & 0x1)) - bfin_write_RTC_PREN(0x1); -} - -/* Our on-chip RTC has no notion of "reset" */ -void rtc_reset(void) -{ - rtc_init(); -} - -/* Wait for pending writes to complete */ -static void wait_for_complete(void) -{ - pr_stamp(); - while (!(bfin_read_RTC_ISTAT() & WRITE_COMPLETE)) - if (!(bfin_read_RTC_ISTAT() & WRITE_PENDING)) - break; - bfin_write_RTC_ISTAT(WRITE_COMPLETE); -} - -/* Set the time. Get the time_in_secs which is the number of seconds since Jan 1970 and set the RTC registers - * based on this value. - */ -int rtc_set(struct rtc_time *tmp) -{ - unsigned long remain, days, hrs, mins, secs; - - pr_stamp(); - - if (tmp == NULL) { - puts("Error setting the date/time\n"); - return -1; - } - - rtc_init(); - wait_for_complete(); - - /* Calculate number of seconds this incoming time represents */ - remain = rtc_mktime(tmp); - - /* Figure out how many days since epoch */ - days = remain / NUM_SECS_IN_DAY; - - /* From the remaining secs, compute the hrs(0-23), mins(0-59) and secs(0-59) */ - remain = remain % NUM_SECS_IN_DAY; - hrs = remain / NUM_SECS_IN_HR; - remain = remain % NUM_SECS_IN_HR; - mins = remain / NUM_SECS_IN_MIN; - secs = remain % NUM_SECS_IN_MIN; - - /* Encode these time values into our RTC_STAT register */ - bfin_write_RTC_STAT(SET_ALARM(days, hrs, mins, secs)); - - return 0; -} - -/* Read the time from the RTC_STAT. time_in_seconds is seconds since Jan 1970 */ -int rtc_get(struct rtc_time *tmp) -{ - uint32_t cur_rtc_stat; - int time_in_sec; - int tm_sec, tm_min, tm_hr, tm_day; - - pr_stamp(); - - if (tmp == NULL) { - puts("Error getting the date/time\n"); - return -1; - } - - rtc_init(); - wait_for_complete(); - - /* Read the RTC_STAT register */ - cur_rtc_stat = bfin_read_RTC_STAT(); - - /* Convert our encoded format into actual time values */ - tm_sec = (cur_rtc_stat & RTC_SEC) >> RTC_SEC_P; - tm_min = (cur_rtc_stat & RTC_MIN) >> RTC_MIN_P; - tm_hr = (cur_rtc_stat & RTC_HR ) >> RTC_HR_P; - tm_day = (cur_rtc_stat & RTC_DAY) >> RTC_DAY_P; - - /* Calculate the total number of seconds since epoch */ - time_in_sec = (tm_sec) + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hr) + DAYS_TO_SECS(tm_day); - rtc_to_tm(time_in_sec, tmp); - - return 0; -} - -#endif diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 3be1da6873..5df15c7fd6 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -16,28 +16,16 @@ #include <common.h> #include <command.h> +#include <dm.h> #include <rtc.h> #include <i2c.h> -#if defined(CONFIG_CMD_DATE) - -/*---------------------------------------------------------------------*/ -#undef DEBUG_RTC - -#ifdef DEBUG_RTC -#define DEBUGR(fmt,args...) printf(fmt ,##args) -#else -#define DEBUGR(fmt,args...) -#endif -/*---------------------------------------------------------------------*/ - -#ifndef CONFIG_SYS_I2C_RTC_ADDR -# define CONFIG_SYS_I2C_RTC_ADDR 0x68 -#endif - -#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000) -# error The DS1307 is specified only up to 100kHz! -#endif +enum ds_type { + ds_1307, + ds_1337, + ds_1340, + mcp794xx, +}; /* * RTC register addresses @@ -62,6 +50,28 @@ #define MCP7941X_BIT_ST 0x80 #define MCP7941X_BIT_VBATEN 0x08 +#ifndef CONFIG_DM_RTC + +#if defined(CONFIG_CMD_DATE) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt, args...) printf(fmt, ##args) +#else +#define DEBUGR(fmt, args...) +#endif +/*---------------------------------------------------------------------*/ + +#ifndef CONFIG_SYS_I2C_RTC_ADDR +# define CONFIG_SYS_I2C_RTC_ADDR 0x68 +#endif + +#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000) +# error The DS1307 is specified only up to 100kHz! +#endif + static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -211,4 +221,163 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } -#endif + +#endif /* CONFIG_CMD_DATE*/ + +#endif /* !CONFIG_DM_RTC */ + +#ifdef CONFIG_DM_RTC +static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + int ret; + uchar buf[7]; + enum ds_type type = dev_get_driver_data(dev); + + 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); + + if (tm->tm_year < 1970 || tm->tm_year > 2069) + printf("WARNING: year should be between 1970 and 2069!\n"); + + buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100); + buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon); + buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1); + buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday); + buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour); + buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min); + buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec); + + if (type == mcp794xx) { + buf[RTC_DAY_REG_ADDR] |= MCP7941X_BIT_VBATEN; + buf[RTC_SEC_REG_ADDR] |= MCP7941X_BIT_ST; + } + + ret = dm_i2c_write(dev, 0, buf, sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + int ret; + uchar buf[7]; + enum ds_type type = dev_get_driver_data(dev); + +read_rtc: + ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret < 0) + return ret; + + if (type == ds_1307) { + if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the CH flag */ + buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; + dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, + buf[RTC_SEC_REG_ADDR]); + return -1; + } + } + + if (type == mcp794xx) { + /* make sure that the backup battery is enabled */ + if (!(buf[RTC_DAY_REG_ADDR] & MCP7941X_BIT_VBATEN)) { + dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, + buf[RTC_DAY_REG_ADDR] | + MCP7941X_BIT_VBATEN); + } + + /* clock halted? turn it on, so clock can tick. */ + if (!(buf[RTC_SEC_REG_ADDR] & MCP7941X_BIT_ST)) { + dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, + MCP7941X_BIT_ST); + printf("Started RTC\n"); + goto read_rtc; + } + } + + tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F); + tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F); + tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F); + tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F); + tm->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F); + tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + + (bcd2bin(buf[RTC_YR_REG_ADDR]) >= 70 ? + 1900 : 2000); + tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] - 1) & 0x07); + tm->tm_yday = 0; + tm->tm_isdst = 0; + + 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; +} + +static int ds1307_rtc_reset(struct udevice *dev) +{ + int ret; + struct rtc_time tmp = { + .tm_year = 1970, + .tm_mon = 1, + .tm_mday = 1, + .tm_hour = 0, + .tm_min = 0, + .tm_sec = 0, + }; + + /* clear Clock Halt */ + ret = dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, 0x00); + if (ret < 0) + return ret; + ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, + RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | + RTC_CTL_BIT_RS0); + if (ret < 0) + return ret; + + ret = ds1307_rtc_set(dev, &tmp); + if (ret < 0) + return ret; + + debug("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n", + tmp.tm_year, tmp.tm_mon, tmp.tm_mday, + tmp.tm_hour, tmp.tm_min, tmp.tm_sec); + + return 0; +} + +static int ds1307_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static const struct rtc_ops ds1307_rtc_ops = { + .get = ds1307_rtc_get, + .set = ds1307_rtc_set, + .reset = ds1307_rtc_reset, +}; + +static const struct udevice_id ds1307_rtc_ids[] = { + { .compatible = "dallas,ds1307", .data = ds_1307 }, + { .compatible = "dallas,ds1337", .data = ds_1337 }, + { .compatible = "dallas,ds1340", .data = ds_1340 }, + { .compatible = "microchip,mcp7941x", .data = mcp794xx }, + { } +}; + +U_BOOT_DRIVER(rtc_ds1307) = { + .name = "rtc-ds1307", + .id = UCLASS_RTC, + .probe = ds1307_probe, + .of_match = ds1307_rtc_ids, + .ops = &ds1307_rtc_ops, +}; +#endif /* CONFIG_DM_RTC */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index c0ec2ec2e4..58320666b7 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,17 @@ config SPL_SERIAL_PRESENT This option enables the full UART in SPL, so if is it disabled, the full UART driver will be omitted, thus saving space. +config CONS_INDEX + int "UART used for console" + depends on ARCH_SUNXI + default 2 if MACH_SUN5I + default 5 if MACH_SUN8I_A23 || MACH_SUN8I_A33 + default 1 + help + Configures the console index. + For Allwinner SoC., default values are 2 for SUN5I and 5 for A23/A33. + Otherwise, the index equals 1. + config DM_SERIAL bool "Enable Driver Model for serial drivers" depends on DM diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c index 2e19813643..29799dce93 100644 --- a/drivers/serial/usbtty.c +++ b/drivers/serial/usbtty.c @@ -850,6 +850,13 @@ static int write_buffer (circbuf_t * buf) struct urb *current_urb = NULL; current_urb = next_urb (device_instance, endpoint); + + if (!current_urb) { + TTYERR ("current_urb is NULL, buf->size %d\n", + buf->size); + return 0; + } + /* TX data still exists - send it now */ if(endpoint->sent < current_urb->actual_length){ @@ -871,12 +878,6 @@ static int write_buffer (circbuf_t * buf) */ while (buf->size > 0) { - if (!current_urb) { - TTYERR ("current_urb is NULL, buf->size %d\n", - buf->size); - return total; - } - dest = (char*)current_urb->buffer + current_urb->actual_length; diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 7649114231..4701b79f16 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -296,6 +296,9 @@ static void atmel_spi_cs_activate(struct udevice *dev) struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); u32 cs = slave_plat->cs; + if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + return; + dm_gpio_set_value(&priv->cs_gpios[cs], 0); } @@ -306,6 +309,9 @@ static void atmel_spi_cs_deactivate(struct udevice *dev) struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); u32 cs = slave_plat->cs; + if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + return; + dm_gpio_set_value(&priv->cs_gpios[cs], 1); } @@ -473,6 +479,9 @@ static int atmel_spi_probe(struct udevice *bus) } for(i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { + if (!dm_gpio_is_valid(&priv->cs_gpios[i])) + continue; + dm_gpio_set_dir_flags(&priv->cs_gpios[i], GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); } diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 8a89450109..76d376ac44 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -692,6 +692,5 @@ U_BOOT_DRIVER(omap3_spi) = { .probe = omap3_spi_probe, .ops = &omap3_spi_ops, .priv_auto_alloc_size = sizeof(struct omap3_spi_priv), - .probe = omap3_spi_probe, }; #endif diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 05358ebf4c..f0434a4413 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -17,6 +17,7 @@ #include <errno.h> #include <asm/arch/stm32.h> #include <asm/arch/stm32_defs.h> +#include <clk.h> DECLARE_GLOBAL_DATA_PTR; @@ -457,7 +458,20 @@ static int stm32_qspi_probe(struct udevice *bus) priv->max_hz = plat->max_hz; - clock_setup(QSPI_CLOCK_CFG); +#ifdef CONFIG_CLK + int ret; + struct clk clk; + ret = clk_get_by_index(bus, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + + if (ret) { + dev_err(bus, "failed to enable clock\n"); + return ret; + } +#endif setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT); diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 5a9b1f0f2e..2b77f1ccdc 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -56,6 +56,8 @@ struct zynq_spi_platdata { struct zynq_spi_regs *regs; u32 frequency; /* input frequency */ u32 speed_hz; + uint deactivate_delay_us; /* Delay to wait after deactivate */ + uint activate_delay_us; /* Delay to wait after activate */ }; /* zynq spi priv */ @@ -63,6 +65,7 @@ struct zynq_spi_priv { struct zynq_spi_regs *regs; u8 cs; u8 mode; + ulong last_transaction_us; /* Time of last transaction end */ u8 fifo_depth; u32 freq; /* required frequency */ }; @@ -78,6 +81,10 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus) /* FIXME: Use 250MHz as a suitable default */ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", 250000000); + plat->deactivate_delay_us = fdtdec_get_int(blob, node, + "spi-deactivate-delay", 0); + plat->activate_delay_us = fdtdec_get_int(blob, node, + "spi-activate-delay", 0); plat->speed_hz = plat->frequency / 2; debug("%s: regs=%p max-frequency=%d\n", __func__, @@ -133,10 +140,19 @@ static int zynq_spi_probe(struct udevice *bus) static void spi_cs_activate(struct udevice *dev) { struct udevice *bus = dev->parent; + struct zynq_spi_platdata *plat = bus->platdata; struct zynq_spi_priv *priv = dev_get_priv(bus); struct zynq_spi_regs *regs = priv->regs; u32 cr; + /* If it's too soon to do another transaction, wait */ + if (plat->deactivate_delay_us && priv->last_transaction_us) { + ulong delay_us; /* The delay completed so far */ + delay_us = timer_get_us() - priv->last_transaction_us; + if (delay_us < plat->deactivate_delay_us) + udelay(plat->deactivate_delay_us - delay_us); + } + clrbits_le32(®s->cr, ZYNQ_SPI_CR_CS_MASK); cr = readl(®s->cr); /* @@ -147,15 +163,23 @@ static void spi_cs_activate(struct udevice *dev) */ cr |= (~(1 << priv->cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK; writel(cr, ®s->cr); + + if (plat->activate_delay_us) + udelay(plat->activate_delay_us); } static void spi_cs_deactivate(struct udevice *dev) { struct udevice *bus = dev->parent; + struct zynq_spi_platdata *plat = bus->platdata; struct zynq_spi_priv *priv = dev_get_priv(bus); struct zynq_spi_regs *regs = priv->regs; setbits_le32(®s->cr, ZYNQ_SPI_CR_CS_MASK); + + /* Remember time of this transaction so we can honour the bus delay */ + if (plat->deactivate_delay_us) + priv->last_transaction_us = timer_get_us(); } static int zynq_spi_claim_bus(struct udevice *dev) diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 05a37b9a14..966463036f 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -13,4 +13,14 @@ config SYSRESET to effect a reset. The uclass will try all available drivers when reset_walk() is called. +if SYSRESET + +config SYSRESET_PSCI + bool "Enable support for PSCI System Reset" + depends on ARM_PSCI_FW + help + Enable PSCI SYSTEM_RESET function call. To use this, PSCI firmware + must be running on your system. + +endif endmenu diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 49b8bb61c6..7bb840649f 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -5,6 +5,7 @@ # obj-$(CONFIG_SYSRESET) += sysreset-uclass.o +obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ROCKCHIP_RK3036) += sysreset_rk3036.o diff --git a/drivers/sysreset/sysreset_ast.c b/drivers/sysreset/sysreset_ast.c index a0ab12851d..3c3f552df8 100644 --- a/drivers/sysreset/sysreset_ast.c +++ b/drivers/sysreset/sysreset_ast.c @@ -8,21 +8,19 @@ #include <dm.h> #include <errno.h> #include <sysreset.h> +#include <wdt.h> #include <asm/io.h> #include <asm/arch/wdt.h> #include <linux/err.h> -/* Number of Watchdog Timer ticks before reset */ -#define AST_WDT_RESET_TIMEOUT 10 -#define AST_WDT_FOR_RESET 0 - static int ast_sysreset_request(struct udevice *dev, enum sysreset_t type) { - struct ast_wdt *wdt = ast_get_wdt(AST_WDT_FOR_RESET); - u32 reset_mode = 0; + struct udevice *wdt; + u32 reset_mode; + int ret = uclass_first_device(UCLASS_WDT, &wdt); - if (IS_ERR(wdt)) - return PTR_ERR(wdt); + if (ret) + return ret; switch (type) { case SYSRESET_WARM: @@ -35,11 +33,11 @@ static int ast_sysreset_request(struct udevice *dev, enum sysreset_t type) return -EPROTONOSUPPORT; } - /* Clear reset mode bits */ - clrsetbits_le32(&wdt->ctrl, - (WDT_CTRL_RESET_MODE_MASK << WDT_CTRL_RESET_MODE_SHIFT), - (reset_mode << WDT_CTRL_RESET_MODE_SHIFT)); - wdt_start(wdt, AST_WDT_RESET_TIMEOUT); + ret = wdt_expire_now(wdt, reset_mode); + if (ret) { + debug("Sysreset failed: %d", ret); + return ret; + } return -EINPROGRESS; } diff --git a/drivers/sysreset/sysreset_psci.c b/drivers/sysreset/sysreset_psci.c new file mode 100644 index 0000000000..a4911b7d8f --- /dev/null +++ b/drivers/sysreset/sysreset_psci.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <sysreset.h> +#include <linux/errno.h> +#include <linux/psci.h> + +static int psci_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + unsigned long function_id; + + switch (type) { + case SYSRESET_WARM: + case SYSRESET_COLD: + function_id = PSCI_0_2_FN_SYSTEM_RESET; + break; + case SYSRESET_POWER: + function_id = PSCI_0_2_FN_SYSTEM_OFF; + break; + default: + return -ENOSYS; + } + + invoke_psci_fn(function_id, 0, 0, 0); + + return -EINPROGRESS; +} + +static struct sysreset_ops psci_sysreset_ops = { + .request = psci_sysreset_request, +}; + +U_BOOT_DRIVER(psci_sysreset) = { + .name = "psci-sysreset", + .id = UCLASS_SYSRESET, + .ops = &psci_sysreset_ops, +}; diff --git a/drivers/sysreset/sysreset_rk3188.c b/drivers/sysreset/sysreset_rk3188.c index 36ae47600a..053a6344f5 100644 --- a/drivers/sysreset/sysreset_rk3188.c +++ b/drivers/sysreset/sysreset_rk3188.c @@ -7,21 +7,36 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <syscon.h> #include <sysreset.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/cru_rk3188.h> +#include <asm/arch/grf_rk3188.h> #include <asm/arch/hardware.h> #include <linux/err.h> int rk3188_sysreset_request(struct udevice *dev, enum sysreset_t type) { struct rk3188_cru *cru = rockchip_get_cru(); + struct rk3188_grf *grf; if (IS_ERR(cru)) return PTR_ERR(cru); switch (type) { case SYSRESET_WARM: + grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + if (IS_ERR(grf)) + return -EPROTONOSUPPORT; + + /* + * warm-reset keeps the remap value, + * so make sure it's disabled. + */ + rk_clrsetreg(&grf->soc_con0, + NOC_REMAP_MASK << NOC_REMAP_SHIFT, + 0 << NOC_REMAP_SHIFT); + rk_clrreg(&cru->cru_mode_con, 0xffff); writel(0xeca8, &cru->cru_glb_srst_snd_value); break; diff --git a/drivers/usb/common/fsl-errata.c b/drivers/usb/common/fsl-errata.c index 6069c935c1..338ac08d8a 100644 --- a/drivers/usb/common/fsl-errata.c +++ b/drivers/usb/common/fsl-errata.c @@ -204,7 +204,7 @@ bool has_erratum_a010151(void) case SVR_LS1043A: return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); #endif -#ifdef CONFIG_LS102XA +#ifdef CONFIG_ARCH_LS1021A case SOC_VER_LS1020: case SOC_VER_LS1021: case SOC_VER_LS1022: diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0bf8274405..fb5aa6f889 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -44,6 +44,15 @@ config USB_XHCI_ZYNQMP help Enables support for the on-chip xHCI controller on Xilinx ZynqMP SoCs. +config USB_XHCI_DRA7XX_INDEX + int "DRA7XX xHCI USB index" + range 0 1 + default 0 + depends on DRA7XX + help + Select the DRA7XX xHCI USB index. + Current supported values: 0, 1. + endif # USB_XHCI_HCD config USB_EHCI_HCD diff --git a/drivers/usb/host/ehci-ppc4xx.c b/drivers/usb/host/ehci-ppc4xx.c index 9aee3ff786..9d23577642 100644 --- a/drivers/usb/host/ehci-ppc4xx.c +++ b/drivers/usb/host/ehci-ppc4xx.c @@ -8,6 +8,7 @@ */ #include <common.h> #include <usb.h> +#include <asm/io.h> #include "ehci.h" diff --git a/drivers/usb/host/xhci-omap.c b/drivers/usb/host/xhci-omap.c index b881b198fc..d6c5744818 100644 --- a/drivers/usb/host/xhci-omap.c +++ b/drivers/usb/host/xhci-omap.c @@ -27,12 +27,27 @@ DECLARE_GLOBAL_DATA_PTR; static struct omap_xhci omap; -__weak int __board_usb_init(int index, enum usb_init_type init) +__weak int omap_xhci_board_usb_init(int index, enum usb_init_type init) { + enable_usb_clocks(index); return 0; } + int board_usb_init(int index, enum usb_init_type init) - __attribute__((weak, alias("__board_usb_init"))); +{ + return omap_xhci_board_usb_init(index, init); +} + +__weak int omap_xhci_board_usb_cleanup(int index, enum usb_init_type init) +{ + disable_usb_clocks(index); + return 0; +} + +int board_usb_cleanup(int index, enum usb_init_type init) +{ + return omap_xhci_board_usb_cleanup(index, init); +} static int omap_xhci_core_init(struct omap_xhci *omap) { diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index ea71f75947..8662c0ff70 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -446,7 +446,7 @@ int musb_register(struct musb_hdrc_platform_data *plat, void *bdata, } *musbp = musb_init_controller(plat, (struct device *)bdata, ctl_regs); - if (!musbp) { + if (!*musbp) { printf("Failed to init the controller\n"); return -EIO; } diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c index 87640f4e32..d643334a2e 100644 --- a/drivers/usb/musb/musb_udc.c +++ b/drivers/usb/musb/musb_udc.c @@ -85,7 +85,7 @@ do { \ /* static implies these initialized to 0 or NULL */ static int debug_setup; static int debug_level; -static struct musb_epinfo epinfo[MAX_ENDPOINT * 2]; +static struct musb_epinfo epinfo[MAX_ENDPOINT * 2 + 2]; static enum ep0_state_enum { IDLE = 0, TX, @@ -944,7 +944,7 @@ int udc_init(void) musbr = musb_cfg.regs; /* Initialize the endpoints */ - for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) { + for (ep_loop = 0; ep_loop <= MAX_ENDPOINT * 2; ep_loop++) { epinfo[ep_loop].epnum = (ep_loop / 2) + 1; epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */ epinfo[ep_loop].epsize = 0; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 19e97452bd..e29c3fcfc6 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -89,6 +89,15 @@ config CONSOLE_TRUETYPE_SIZE method to select the display's physical size, which would allow U-Boot to calculate the correct font size. +config SYS_WHITE_ON_BLACK + bool "Display console as white on a black background" + default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || TEGRA || X86 + help + Normally the display is black on a white background, Enable this + option to invert this, i.e. white on a black background. This can be + better in low-light situations or to reduce eye strain in some + cases. + source "drivers/video/fonts/Kconfig" config VIDCONSOLE_AS_LCD diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 7cd6d28658..a80af3104d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -51,7 +51,6 @@ obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o obj-$(CONFIG_VIDEO_SM501) += sm501.o -obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o videomodes.o obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_VIDEO_VESA) += vesa.o @@ -64,3 +63,4 @@ obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-y += bridge/ +obj-y += sunxi/ diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile new file mode 100644 index 0000000000..b8afd892ad --- /dev/null +++ b/drivers/video/sunxi/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o ../videomodes.o +obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o diff --git a/drivers/video/sunxi/lcdc.c b/drivers/video/sunxi/lcdc.c new file mode 100644 index 0000000000..7d215b713e --- /dev/null +++ b/drivers/video/sunxi/lcdc.c @@ -0,0 +1,209 @@ +/* + * Timing controller driver for Allwinner SoCs. + * + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> + * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com> + * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#include <asm/arch/lcdc.h> +#include <asm/io.h> + +static int lcdc_get_clk_delay(const struct display_timing *mode, int tcon) +{ + int delay; + + delay = mode->vfront_porch.typ + mode->vsync_len.typ + + mode->vback_porch.typ; + if (mode->flags & DISPLAY_FLAGS_INTERLACED) + delay /= 2; + if (tcon == 1) + delay -= 2; + + return (delay > 30) ? 30 : delay; +} + +void lcdc_init(struct sunxi_lcdc_reg * const lcdc) +{ + /* Init lcdc */ + writel(0, &lcdc->ctrl); /* Disable tcon */ + writel(0, &lcdc->int0); /* Disable all interrupts */ + + /* Disable tcon0 dot clock */ + clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE); + + /* Set all io lines to tristate */ + writel(0xffffffff, &lcdc->tcon0_io_tristate); + writel(0xffffffff, &lcdc->tcon1_io_tristate); +} + +void lcdc_enable(struct sunxi_lcdc_reg * const lcdc, int depth) +{ + setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE); +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE); + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0); +#ifdef CONFIG_SUNXI_GEN_SUN6I + udelay(2); /* delay at least 1200 ns */ + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB); + udelay(2); /* delay at least 1200 ns */ + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC); + if (depth == 18) + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7)); + else + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf)); +#else + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE); + udelay(2); /* delay at least 1200 ns */ + setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1); + udelay(1); /* delay at least 120 ns */ + setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2); + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE); +#endif +#endif +} + +void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc, + const struct display_timing *mode, + int clk_div, bool for_ext_vga_dac, + int depth, int dclk_phase) +{ + int bp, clk_delay, total, val; + +#ifndef CONFIG_SUNXI_DE2 + /* Use tcon0 */ + clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, + SUNXI_LCDC_CTRL_IO_MAP_TCON0); +#endif + + clk_delay = lcdc_get_clk_delay(mode, 0); + writel(SUNXI_LCDC_TCON0_CTRL_ENABLE | + SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl); + + writel(SUNXI_LCDC_TCON0_DCLK_ENABLE | + SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk); + + writel(SUNXI_LCDC_X(mode->hactive.typ) | + SUNXI_LCDC_Y(mode->vactive.typ), &lcdc->tcon0_timing_active); + + bp = mode->hsync_len.typ + mode->hback_porch.typ; + total = mode->hactive.typ + mode->hfront_porch.typ + bp; + writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) | + SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h); + + bp = mode->vsync_len.typ + mode->vback_porch.typ; + total = mode->vactive.typ + mode->vfront_porch.typ + bp; + writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) | + SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v); + +#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL + writel(SUNXI_LCDC_X(mode->hsync_len.typ) | + SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon0_timing_sync); + + writel(0, &lcdc->tcon0_hv_intf); + writel(0, &lcdc->tcon0_cpu_intf); +#endif +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + val = (depth == 18) ? 1 : 0; + writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) | + SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf); +#endif + + if (depth == 18 || depth == 16) { + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]); + writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]); + writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]); + writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]); + writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]); + writel(((depth == 18) ? + SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 : + SUNXI_LCDC_TCON0_FRM_CTRL_RGB565), + &lcdc->tcon0_frm_ctrl); + } + + val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(dclk_phase); + if (mode->flags & DISPLAY_FLAGS_HSYNC_LOW) + val |= SUNXI_LCDC_TCON_HSYNC_MASK; + if (mode->flags & DISPLAY_FLAGS_VSYNC_LOW) + val |= SUNXI_LCDC_TCON_VSYNC_MASK; + +#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH + if (for_ext_vga_dac) + val = 0; +#endif + writel(val, &lcdc->tcon0_io_polarity); + + writel(0, &lcdc->tcon0_io_tristate); +} + +void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc, + const struct display_timing *mode, + bool ext_hvsync, bool is_composite) +{ + int bp, clk_delay, total, val, yres; + +#ifndef CONFIG_SUNXI_DE2 + /* Use tcon1 */ + clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, + SUNXI_LCDC_CTRL_IO_MAP_TCON1); +#endif + + clk_delay = lcdc_get_clk_delay(mode, 1); + writel(SUNXI_LCDC_TCON1_CTRL_ENABLE | + ((mode->flags & DISPLAY_FLAGS_INTERLACED) ? + SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) | + SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl); + + yres = mode->vactive.typ; + if (mode->flags & DISPLAY_FLAGS_INTERLACED) + yres /= 2; + writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres), + &lcdc->tcon1_timing_source); + writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres), + &lcdc->tcon1_timing_scale); + writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres), + &lcdc->tcon1_timing_out); + + bp = mode->hsync_len.typ + mode->hback_porch.typ; + total = mode->hactive.typ + mode->hfront_porch.typ + bp; + writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) | + SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h); + + bp = mode->vsync_len.typ + mode->vback_porch.typ; + total = mode->vactive.typ + mode->vfront_porch.typ + bp; + if (!(mode->flags & DISPLAY_FLAGS_INTERLACED)) + total *= 2; + writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) | + SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v); + + writel(SUNXI_LCDC_X(mode->hsync_len.typ) | + SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon1_timing_sync); + + if (ext_hvsync) { + val = 0; + if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) + val |= SUNXI_LCDC_TCON_HSYNC_MASK; + if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) + val |= SUNXI_LCDC_TCON_VSYNC_MASK; + writel(val, &lcdc->tcon1_io_polarity); + + clrbits_le32(&lcdc->tcon1_io_tristate, + SUNXI_LCDC_TCON_VSYNC_MASK | + SUNXI_LCDC_TCON_HSYNC_MASK); + } + +#ifdef CONFIG_MACH_SUN5I + if (is_composite) + clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK, + SUNXI_LCDC_MUX_CTRL_SRC0(1)); +#endif +} diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c new file mode 100644 index 0000000000..9a32c3a020 --- /dev/null +++ b/drivers/video/sunxi/sunxi_de2.c @@ -0,0 +1,258 @@ +/* + * Allwinner DE2 display driver + * + * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <edid.h> +#include <video.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/display2.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + /* Maximum LCD size we support */ + LCD_MAX_WIDTH = 3840, + LCD_MAX_HEIGHT = 2160, + LCD_MAX_LOG2_BPP = VIDEO_BPP32, +}; + +static void sunxi_de2_composer_init(void) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + +#ifdef CONFIG_MACH_SUN50I + u32 reg_value; + + /* set SRAM for video use (A64 only) */ + reg_value = readl(SUNXI_SRAMC_BASE + 0x04); + reg_value &= ~(0x01 << 24); + writel(reg_value, SUNXI_SRAMC_BASE + 0x04); +#endif + + clock_set_pll10(432000000); + + /* Set DE parent to pll10 */ + clrsetbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_PLL_MASK, + CCM_DE2_CTRL_PLL10); + + /* Set ahb gating to pass */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE); + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE); + + /* Clock on */ + setbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_GATE); +} + +static void sunxi_de2_mode_set(int mux, const struct display_timing *mode, + int bpp, ulong address) +{ + ulong de_mux_base = (mux == 0) ? + SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE; + struct de_clk * const de_clk_regs = + (struct de_clk *)(SUNXI_DE2_BASE); + struct de_glb * const de_glb_regs = + (struct de_glb *)(de_mux_base + + SUNXI_DE2_MUX_GLB_REGS); + struct de_bld * const de_bld_regs = + (struct de_bld *)(de_mux_base + + SUNXI_DE2_MUX_BLD_REGS); + struct de_ui * const de_ui_regs = + (struct de_ui *)(de_mux_base + + SUNXI_DE2_MUX_CHAN_REGS + + SUNXI_DE2_MUX_CHAN_SZ * 1); + u32 size = SUNXI_DE2_WH(mode->hactive.typ, mode->vactive.typ); + int channel; + u32 format; + + /* enable clock */ +#ifdef CONFIG_MACH_SUN8I_H3 + setbits_le32(&de_clk_regs->rst_cfg, (mux == 0) ? 1 : 4); +#else + setbits_le32(&de_clk_regs->rst_cfg, BIT(mux)); +#endif + setbits_le32(&de_clk_regs->gate_cfg, BIT(mux)); + setbits_le32(&de_clk_regs->bus_cfg, BIT(mux)); + + clrbits_le32(&de_clk_regs->sel_cfg, 1); + + writel(SUNXI_DE2_MUX_GLB_CTL_EN, &de_glb_regs->ctl); + writel(0, &de_glb_regs->status); + writel(1, &de_glb_regs->dbuff); + writel(size, &de_glb_regs->size); + + for (channel = 0; channel < 4; channel++) { + void *ch = (void *)(de_mux_base + SUNXI_DE2_MUX_CHAN_REGS + + SUNXI_DE2_MUX_CHAN_SZ * channel); + memset(ch, 0, (channel == 0) ? + sizeof(struct de_vi) : sizeof(struct de_ui)); + } + memset(de_bld_regs, 0, sizeof(struct de_bld)); + + writel(0x00000101, &de_bld_regs->fcolor_ctl); + + writel(1, &de_bld_regs->route); + + writel(0, &de_bld_regs->premultiply); + writel(0xff000000, &de_bld_regs->bkcolor); + + writel(0x03010301, &de_bld_regs->bld_mode[0]); + + writel(size, &de_bld_regs->output_size); + writel(mode->flags & DISPLAY_FLAGS_INTERLACED ? 2 : 0, + &de_bld_regs->out_ctl); + writel(0, &de_bld_regs->ck_ctl); + + writel(0xff000000, &de_bld_regs->attr[0].fcolor); + writel(size, &de_bld_regs->attr[0].insize); + + /* Disable all other units */ + writel(0, de_mux_base + SUNXI_DE2_MUX_VSU_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_GSU1_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_GSU2_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_GSU3_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_FCE_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_BWS_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_LTI_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_PEAK_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_ASE_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_FCC_REGS); + writel(0, de_mux_base + SUNXI_DE2_MUX_DCSC_REGS); + + switch (bpp) { + case 16: + format = SUNXI_DE2_UI_CFG_ATTR_FMT(SUNXI_DE2_FORMAT_RGB_565); + break; + case 32: + default: + format = SUNXI_DE2_UI_CFG_ATTR_FMT(SUNXI_DE2_FORMAT_XRGB_8888); + break; + } + + writel(SUNXI_DE2_UI_CFG_ATTR_EN | format, &de_ui_regs->cfg[0].attr); + writel(size, &de_ui_regs->cfg[0].size); + writel(0, &de_ui_regs->cfg[0].coord); + writel((bpp / 8) * mode->hactive.typ, &de_ui_regs->cfg[0].pitch); + writel(address, &de_ui_regs->cfg[0].top_laddr); + writel(size, &de_ui_regs->ovl_size); + + /* apply settings */ + writel(1, &de_glb_regs->dbuff); +} + +static int sunxi_de2_init(struct udevice *dev, ulong fbbase, + enum video_log2_bpp l2bpp, + struct udevice *disp, int mux) +{ + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct display_timing timing; + struct display_plat *disp_uc_plat; + int ret; + + disp_uc_plat = dev_get_uclass_platdata(disp); + debug("Using device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat); + if (display_in_use(disp)) { + debug(" - device in use\n"); + return -EBUSY; + } + + disp_uc_plat->source_id = mux; + + ret = device_probe(disp); + if (ret) { + debug("%s: device '%s' display won't probe (ret=%d)\n", + __func__, dev->name, ret); + return ret; + } + + ret = display_read_timing(disp, &timing); + if (ret) { + debug("%s: Failed to read timings\n", __func__); + return ret; + } + + sunxi_de2_composer_init(); + sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase); + + ret = display_enable(disp, 1 << l2bpp, &timing); + if (ret) { + debug("%s: Failed to enable display\n", __func__); + return ret; + } + + uc_priv->xsize = timing.hactive.typ; + uc_priv->ysize = timing.vactive.typ; + uc_priv->bpix = l2bpp; + debug("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize); + + return 0; +} + +static int sunxi_de2_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct udevice *disp; + int ret; + int mux; + + /* Before relocation we don't need to do anything */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + ret = uclass_find_device_by_name(UCLASS_DISPLAY, + "sunxi_dw_hdmi", &disp); + if (ret) { + debug("%s: hdmi display not found (ret=%d)\n", __func__, ret); + return ret; + } + + if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5)) + mux = 0; + else + mux = 1; + + ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux); + if (ret) + return ret; + + video_set_flush_dcache(dev, 1); + + return 0; +} + +static int sunxi_de2_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + + plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << LCD_MAX_LOG2_BPP) / 8; + + return 0; +} + +static const struct video_ops sunxi_de2_ops = { +}; + +U_BOOT_DRIVER(sunxi_de2) = { + .name = "sunxi_de2", + .id = UCLASS_VIDEO, + .ops = &sunxi_de2_ops, + .bind = sunxi_de2_bind, + .probe = sunxi_de2_probe, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DEVICE(sunxi_de2) = { + .name = "sunxi_de2" +}; diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 6f8ee01c10..92c9d06054 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -12,6 +12,7 @@ #include <asm/arch/clock.h> #include <asm/arch/display.h> #include <asm/arch/gpio.h> +#include <asm/arch/lcdc.h> #include <asm/arch/pwm.h> #include <asm/global_data.h> #include <asm/gpio.h> @@ -23,10 +24,10 @@ #include <i2c.h> #include <malloc.h> #include <video_fb.h> -#include "videomodes.h" -#include "anx9804.h" -#include "hitachi_tx18d42vm_lcd.h" -#include "ssd2828.h" +#include "../videomodes.h" +#include "../anx9804.h" +#include "../hitachi_tx18d42vm_lcd.h" +#include "../ssd2828.h" #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW #define PWM_ON 0 @@ -650,45 +651,7 @@ static void sunxi_lcdc_init(void) #endif #endif - /* Init lcdc */ - writel(0, &lcdc->ctrl); /* Disable tcon */ - writel(0, &lcdc->int0); /* Disable all interrupts */ - - /* Disable tcon0 dot clock */ - clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE); - - /* Set all io lines to tristate */ - writel(0xffffffff, &lcdc->tcon0_io_tristate); - writel(0xffffffff, &lcdc->tcon1_io_tristate); -} - -static void sunxi_lcdc_enable(void) -{ - struct sunxi_lcdc_reg * const lcdc = - (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; - - setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE); -#ifdef CONFIG_VIDEO_LCD_IF_LVDS - setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE); - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0); -#ifdef CONFIG_SUNXI_GEN_SUN6I - udelay(2); /* delay at least 1200 ns */ - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB); - udelay(2); /* delay at least 1200 ns */ - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC); - if (sunxi_display.depth == 18) - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7)); - else - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf)); -#else - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE); - udelay(2); /* delay at least 1200 ns */ - setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1); - udelay(1); /* delay at least 120 ns */ - setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2); - setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE); -#endif -#endif + lcdc_init(lcdc); } static void sunxi_lcdc_panel_enable(void) @@ -758,17 +721,31 @@ static void sunxi_lcdc_backlight_enable(void) gpio_direction_output(pin, PWM_ON); } -static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon) +static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode, + struct display_timing *timing) { - int delay; + timing->pixelclock.typ = mode->pixclock_khz * 1000; - delay = mode->lower_margin + mode->vsync_len + mode->upper_margin; - if (mode->vmode == FB_VMODE_INTERLACED) - delay /= 2; - if (tcon == 1) - delay -= 2; + timing->hactive.typ = mode->xres; + timing->hfront_porch.typ = mode->right_margin; + timing->hback_porch.typ = mode->left_margin; + timing->hsync_len.typ = mode->hsync_len; - return (delay > 30) ? 30 : delay; + timing->vactive.typ = mode->yres; + timing->vfront_porch.typ = mode->lower_margin; + timing->vback_porch.typ = mode->upper_margin; + timing->vsync_len.typ = mode->vsync_len; + + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) + timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH; + else + timing->flags |= DISPLAY_FLAGS_HSYNC_LOW; + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH; + else + timing->flags |= DISPLAY_FLAGS_VSYNC_LOW; + if (mode->vmode == FB_VMODE_INTERLACED) + timing->flags |= DISPLAY_FLAGS_INTERLACED; } static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, @@ -776,7 +753,8 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, { struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; - int bp, clk_delay, clk_div, clk_double, pin, total, val; + int clk_div, clk_double, pin; + struct display_timing timing; #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) { @@ -796,73 +774,9 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double); - /* Use tcon0 */ - clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, - SUNXI_LCDC_CTRL_IO_MAP_TCON0); - - clk_delay = sunxi_lcdc_get_clk_delay(mode, 0); - writel(SUNXI_LCDC_TCON0_CTRL_ENABLE | - SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl); - - writel(SUNXI_LCDC_TCON0_DCLK_ENABLE | - SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk); - - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), - &lcdc->tcon0_timing_active); - - bp = mode->hsync_len + mode->left_margin; - total = mode->xres + mode->right_margin + bp; - writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) | - SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h); - - bp = mode->vsync_len + mode->upper_margin; - total = mode->yres + mode->lower_margin + bp; - writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) | - SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v); - -#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL - writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len), - &lcdc->tcon0_timing_sync); - - writel(0, &lcdc->tcon0_hv_intf); - writel(0, &lcdc->tcon0_cpu_intf); -#endif -#ifdef CONFIG_VIDEO_LCD_IF_LVDS - val = (sunxi_display.depth == 18) ? 1 : 0; - writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) | - SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf); -#endif - - if (sunxi_display.depth == 18 || sunxi_display.depth == 16) { - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]); - writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]); - writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]); - writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]); - writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]); - writel(((sunxi_display.depth == 18) ? - SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 : - SUNXI_LCDC_TCON0_FRM_CTRL_RGB565), - &lcdc->tcon0_frm_ctrl); - } - - val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE); - if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) - val |= SUNXI_LCDC_TCON_HSYNC_MASK; - if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) - val |= SUNXI_LCDC_TCON_VSYNC_MASK; - -#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH - if (for_ext_vga_dac) - val = 0; -#endif - writel(val, &lcdc->tcon0_io_polarity); - - writel(0, &lcdc->tcon0_io_tristate); + sunxi_ctfb_mode_to_display_timing(mode, &timing); + lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac, + sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE); } #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE @@ -872,65 +786,17 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, { struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; - int bp, clk_delay, total, val, yres; - - /* Use tcon1 */ - clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, - SUNXI_LCDC_CTRL_IO_MAP_TCON1); + struct display_timing timing; - clk_delay = sunxi_lcdc_get_clk_delay(mode, 1); - writel(SUNXI_LCDC_TCON1_CTRL_ENABLE | - ((mode->vmode == FB_VMODE_INTERLACED) ? - SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) | - SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl); - - yres = mode->yres; - if (mode->vmode == FB_VMODE_INTERLACED) - yres /= 2; - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), - &lcdc->tcon1_timing_source); - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), - &lcdc->tcon1_timing_scale); - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), - &lcdc->tcon1_timing_out); - - bp = mode->hsync_len + mode->left_margin; - total = mode->xres + mode->right_margin + bp; - writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) | - SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h); - - bp = mode->vsync_len + mode->upper_margin; - total = mode->yres + mode->lower_margin + bp; - if (mode->vmode == FB_VMODE_NONINTERLACED) - total *= 2; - writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) | - SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v); - - writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len), - &lcdc->tcon1_timing_sync); + sunxi_ctfb_mode_to_display_timing(mode, &timing); + lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync, + sunxi_is_composite()); if (use_portd_hvsync) { sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0); sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0); - - val = 0; - if (mode->sync & FB_SYNC_HOR_HIGH_ACT) - val |= SUNXI_LCDC_TCON_HSYNC_MASK; - if (mode->sync & FB_SYNC_VERT_HIGH_ACT) - val |= SUNXI_LCDC_TCON_VSYNC_MASK; - writel(val, &lcdc->tcon1_io_polarity); - - clrbits_le32(&lcdc->tcon1_io_tristate, - SUNXI_LCDC_TCON_VSYNC_MASK | - SUNXI_LCDC_TCON_HSYNC_MASK); } -#ifdef CONFIG_MACH_SUN5I - if (sunxi_is_composite()) - clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK, - SUNXI_LCDC_MUX_CTRL_SRC0(1)); -#endif - sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double); } #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */ @@ -1212,6 +1078,8 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, unsigned int address) { int __maybe_unused clk_div, clk_double; + struct sunxi_lcdc_reg * const lcdc = + (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; switch (sunxi_display.monitor) { case sunxi_monitor_none: @@ -1223,7 +1091,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); sunxi_hdmi_mode_set(mode, clk_div, clk_double); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_hdmi_enable(); #endif break; @@ -1253,7 +1121,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon0_mode_set(mode, false); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); #ifdef CONFIG_VIDEO_LCD_SSD2828 sunxi_ssd2828_init(mode); #endif @@ -1265,13 +1133,13 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1); sunxi_tvencoder_mode_set(); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_tvencoder_enable(); #elif defined CONFIG_VIDEO_VGA_VIA_LCD sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon0_mode_set(mode, true); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_vga_external_dac_enable(); #endif break; @@ -1284,7 +1152,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); sunxi_tvencoder_mode_set(); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_tvencoder_enable(); #endif break; diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c new file mode 100644 index 0000000000..33920a2b67 --- /dev/null +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -0,0 +1,389 @@ +/* + * Allwinner DW HDMI bridge + * + * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <display.h> +#include <dm.h> +#include <dw_hdmi.h> +#include <edid.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/lcdc.h> + +struct sunxi_dw_hdmi_priv { + struct dw_hdmi hdmi; + int mux; +}; + +struct sunxi_hdmi_phy { + u32 pol; + u32 res1[3]; + u32 read_en; + u32 unscramble; + u32 res2[2]; + u32 ctrl; + u32 unk1; + u32 unk2; + u32 pll; + u32 clk; + u32 unk3; + u32 status; +}; + +#define HDMI_PHY_OFFS 0x10000 + +static int sunxi_dw_hdmi_get_divider(uint clock) +{ + /* + * Due to missing documentaion of HDMI PHY, we know correct + * settings only for following four PHY dividers. Select one + * based on clock speed. + */ + if (clock <= 27000000) + return 11; + else if (clock <= 74250000) + return 4; + else if (clock <= 148500000) + return 2; + else + return 1; +} + +static void sunxi_dw_hdmi_phy_init(void) +{ + struct sunxi_hdmi_phy * const phy = + (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + unsigned long tmo; + u32 tmp; + + /* + * HDMI PHY settings are taken as-is from Allwinner BSP code. + * There is no documentation. + */ + writel(0, &phy->ctrl); + setbits_le32(&phy->ctrl, BIT(0)); + udelay(5); + setbits_le32(&phy->ctrl, BIT(16)); + setbits_le32(&phy->ctrl, BIT(1)); + udelay(10); + setbits_le32(&phy->ctrl, BIT(2)); + udelay(5); + setbits_le32(&phy->ctrl, BIT(3)); + udelay(40); + setbits_le32(&phy->ctrl, BIT(19)); + udelay(100); + setbits_le32(&phy->ctrl, BIT(18)); + setbits_le32(&phy->ctrl, 7 << 4); + + /* Note that Allwinner code doesn't fail in case of timeout */ + tmo = timer_get_us() + 2000; + while ((readl(&phy->status) & 0x80) == 0) { + if (timer_get_us() > tmo) { + printf("Warning: HDMI PHY init timeout!\n"); + break; + } + } + + setbits_le32(&phy->ctrl, 0xf << 8); + setbits_le32(&phy->ctrl, BIT(7)); + + writel(0x39dc5040, &phy->pll); + writel(0x80084343, &phy->clk); + udelay(10000); + writel(1, &phy->unk3); + setbits_le32(&phy->pll, BIT(25)); + udelay(100000); + tmp = (readl(&phy->status) & 0x1f800) >> 11; + setbits_le32(&phy->pll, BIT(31) | BIT(30)); + setbits_le32(&phy->pll, tmp); + writel(0x01FF0F7F, &phy->ctrl); + writel(0x80639000, &phy->unk1); + writel(0x0F81C405, &phy->unk2); + + /* enable read access to HDMI controller */ + writel(0x54524545, &phy->read_en); + /* descramble register offsets */ + writel(0x42494E47, &phy->unscramble); +} + +static int sunxi_dw_hdmi_get_plug_in_status(void) +{ + struct sunxi_hdmi_phy * const phy = + (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + + return !!(readl(&phy->status) & (1 << 19)); +} + +static int sunxi_dw_hdmi_wait_for_hpd(void) +{ + ulong start; + + start = get_timer(0); + do { + if (sunxi_dw_hdmi_get_plug_in_status()) + return 0; + udelay(100); + } while (get_timer(start) < 300); + + return -1; +} + +static void sunxi_dw_hdmi_phy_set(uint clock) +{ + struct sunxi_hdmi_phy * const phy = + (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + int div = sunxi_dw_hdmi_get_divider(clock); + u32 tmp; + + /* + * Unfortunately, we don't know much about those magic + * numbers. They are taken from Allwinner BSP driver. + */ + switch (div) { + case 1: + writel(0x30dc5fc0, &phy->pll); + writel(0x800863C0, &phy->clk); + mdelay(10); + writel(0x00000001, &phy->unk3); + setbits_le32(&phy->pll, BIT(25)); + mdelay(200); + tmp = (readl(&phy->status) & 0x1f800) >> 11; + setbits_le32(&phy->pll, BIT(31) | BIT(30)); + if (tmp < 0x3d) + setbits_le32(&phy->pll, tmp + 2); + else + setbits_le32(&phy->pll, 0x3f); + mdelay(100); + writel(0x01FFFF7F, &phy->ctrl); + writel(0x8063b000, &phy->unk1); + writel(0x0F8246B5, &phy->unk2); + break; + case 2: + writel(0x39dc5040, &phy->pll); + writel(0x80084381, &phy->clk); + mdelay(10); + writel(0x00000001, &phy->unk3); + setbits_le32(&phy->pll, BIT(25)); + mdelay(100); + tmp = (readl(&phy->status) & 0x1f800) >> 11; + setbits_le32(&phy->pll, BIT(31) | BIT(30)); + setbits_le32(&phy->pll, tmp); + writel(0x01FFFF7F, &phy->ctrl); + writel(0x8063a800, &phy->unk1); + writel(0x0F81C485, &phy->unk2); + break; + case 4: + writel(0x39dc5040, &phy->pll); + writel(0x80084343, &phy->clk); + mdelay(10); + writel(0x00000001, &phy->unk3); + setbits_le32(&phy->pll, BIT(25)); + mdelay(100); + tmp = (readl(&phy->status) & 0x1f800) >> 11; + setbits_le32(&phy->pll, BIT(31) | BIT(30)); + setbits_le32(&phy->pll, tmp); + writel(0x01FFFF7F, &phy->ctrl); + writel(0x8063b000, &phy->unk1); + writel(0x0F81C405, &phy->unk2); + break; + case 11: + writel(0x39dc5040, &phy->pll); + writel(0x8008430a, &phy->clk); + mdelay(10); + writel(0x00000001, &phy->unk3); + setbits_le32(&phy->pll, BIT(25)); + mdelay(100); + tmp = (readl(&phy->status) & 0x1f800) >> 11; + setbits_le32(&phy->pll, BIT(31) | BIT(30)); + setbits_le32(&phy->pll, tmp); + writel(0x01FFFF7F, &phy->ctrl); + writel(0x8063b000, &phy->unk1); + writel(0x0F81C405, &phy->unk2); + break; + } +} + +static void sunxi_dw_hdmi_pll_set(uint clk_khz) +{ + int value, n, m, div = 0, diff; + int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF; + + div = sunxi_dw_hdmi_get_divider(clk_khz * 1000); + + /* + * Find the lowest divider resulting in a matching clock. If there + * is no match, pick the closest lower clock, as monitors tend to + * not sync to higher frequencies. + */ + for (m = 1; m <= 16; m++) { + n = (m * div * clk_khz) / 24000; + + if ((n >= 1) && (n <= 128)) { + value = (24000 * n) / m / div; + diff = clk_khz - value; + if (diff < best_diff) { + best_diff = diff; + best_m = m; + best_n = n; + } + } + } + + clock_set_pll3_factors(best_m, best_n); + debug("dotclock: %dkHz = %dkHz: (24MHz * %d) / %d / %d\n", + clk_khz, (clock_get_pll3() / 1000) / div, + best_n, best_m, div); +} + +static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid, + int bpp) +{ + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int div = sunxi_dw_hdmi_get_divider(edid->pixelclock.typ); + struct sunxi_lcdc_reg *lcdc; + + if (mux == 0) { + lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; + + /* Reset off */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD0); + + /* Clock on */ + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0); + writel(CCM_LCD0_CTRL_GATE | CCM_LCD0_CTRL_M(div), + &ccm->lcd0_clk_cfg); + } else { + lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD1_BASE; + + /* Reset off */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_LCD1); + + /* Clock on */ + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD1); + writel(CCM_LCD1_CTRL_GATE | CCM_LCD1_CTRL_M(div), + &ccm->lcd1_clk_cfg); + } + + lcdc_init(lcdc); + lcdc_tcon1_mode_set(lcdc, edid, false, false); + lcdc_enable(lcdc, bpp); +} + +static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock) +{ + sunxi_dw_hdmi_pll_set(mpixelclock/1000); + sunxi_dw_hdmi_phy_set(mpixelclock); + + return 0; +} + +static int sunxi_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) +{ + struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + + return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size); +} + +static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *edid) +{ + struct sunxi_hdmi_phy * const phy = + (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS); + struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + int ret; + + ret = dw_hdmi_enable(&priv->hdmi, edid); + if (ret) + return ret; + + sunxi_dw_hdmi_lcdc_init(priv->mux, edid, panel_bpp); + + /* + * Condition in original code is a bit weird. This is attempt + * to make it more reasonable and it works. It could be that + * bits and conditions are related and should be separated. + */ + if (!((edid->flags & DISPLAY_FLAGS_HSYNC_HIGH) && + (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH))) { + setbits_le32(&phy->pol, 0x300); + } + + setbits_le32(&phy->ctrl, 0xf << 12); + + /* + * This is last hdmi access before boot, so scramble addresses + * again or othwerwise BSP driver won't work. Dummy read is + * needed or otherwise last write doesn't get written correctly. + */ + (void)readb(SUNXI_HDMI_BASE); + writel(0, &phy->unscramble); + + return 0; +} + +static int sunxi_dw_hdmi_probe(struct udevice *dev) +{ + struct display_plat *uc_plat = dev_get_uclass_platdata(dev); + struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev); + struct sunxi_ccm_reg * const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int ret; + + /* Set pll3 to 297 MHz */ + clock_set_pll3(297000000); + + /* Set hdmi parent to pll3 */ + clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK, + CCM_HDMI_CTRL_PLL3); + + /* Set ahb gating to pass */ + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI); + setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI2); + setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI); + setbits_le32(&ccm->hdmi_slow_clk_cfg, CCM_HDMI_SLOW_CTRL_DDC_GATE); + + /* Clock on */ + setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE); + + sunxi_dw_hdmi_phy_init(); + + ret = sunxi_dw_hdmi_wait_for_hpd(); + if (ret < 0) { + debug("hdmi can not get hpd signal\n"); + return -1; + } + + priv->hdmi.ioaddr = SUNXI_HDMI_BASE; + priv->hdmi.i2c_clk_high = 0xd8; + priv->hdmi.i2c_clk_low = 0xfe; + priv->hdmi.reg_io_width = 1; + priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; + priv->mux = uc_plat->source_id; + + dw_hdmi_init(&priv->hdmi); + + return 0; +} + +static const struct dm_display_ops sunxi_dw_hdmi_ops = { + .read_edid = sunxi_dw_hdmi_read_edid, + .enable = sunxi_dw_hdmi_enable, +}; + +U_BOOT_DRIVER(sunxi_dw_hdmi) = { + .name = "sunxi_dw_hdmi", + .id = UCLASS_DISPLAY, + .ops = &sunxi_dw_hdmi_ops, + .probe = sunxi_dw_hdmi_probe, + .priv_auto_alloc_size = sizeof(struct sunxi_dw_hdmi_priv), +}; + +U_BOOT_DEVICE(sunxi_dw_hdmi) = { + .name = "sunxi_dw_hdmi" +}; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dbdaafc149..2034e3c620 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1,8 +1,37 @@ -menu "WATCHDOG support" +menu "Watchdog Timer Support" config ULP_WATCHDOG bool "i.MX7ULP watchdog" help Say Y here to enable i.MX7ULP watchdog driver. +config WDT + bool "Enable driver model for watchdog timer drivers" + depends on DM + help + Enable driver model for watchdog timer. At the moment the API + is very simple and only supports four operations: + start, restart, stop and reset (expire immediately). + What exactly happens when the timer expires is up to a particular + device/driver. + +config WDT_SANDBOX + bool "Enable Watchdog Timer support for Sandbox" + depends on SANDBOX && WDT + help + Enable Watchdog Timer support in Sandbox. This is a dummy device that + can be probed and supports all of the methods of WDT, but does not + really do anything. + +config WDT_ASPEED + bool "Aspeed ast2400/ast2500 watchdog timer support" + depends on WDT + default y if ARCH_ASPEED + help + Select this to enable watchdog timer for Aspeed ast2500/ast2400 devices. + The watchdog timer is stopped when initialized. It performs reset, either + full SoC reset or CPU or just some peripherals, based on the flags. + It currently does not support Boot Flash Addressing Mode Detection or + Second Boot. + endmenu diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index dea18363ca..dfc7fbda4a 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -12,7 +12,9 @@ obj-y += imx_watchdog.o endif obj-$(CONFIG_S5P) += s5p_wdt.o obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o -obj-$(CONFIG_BFIN_WATCHDOG) += bfin_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o +obj-$(CONFIG_WDT) += wdt-uclass.o +obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o +obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o diff --git a/drivers/watchdog/ast_wdt.c b/drivers/watchdog/ast_wdt.c new file mode 100644 index 0000000000..b2bd912ad5 --- /dev/null +++ b/drivers/watchdog/ast_wdt.c @@ -0,0 +1,125 @@ +/* + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/wdt.h> + +#define WDT_AST2500 2500 +#define WDT_AST2400 2400 + +DECLARE_GLOBAL_DATA_PTR; + +struct ast_wdt_priv { + struct ast_wdt *regs; +}; + +static int ast_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + ulong driver_data = dev_get_driver_data(dev); + u32 reset_mode = ast_reset_mode_from_flags(flags); + + clrsetbits_le32(&priv->regs->ctrl, + WDT_CTRL_RESET_MASK << WDT_CTRL_RESET_MODE_SHIFT, + reset_mode << WDT_CTRL_RESET_MODE_SHIFT); + + if (driver_data >= WDT_AST2500 && reset_mode == WDT_CTRL_RESET_SOC) + writel(ast_reset_mask_from_flags(flags), + &priv->regs->reset_mask); + + writel((u32) timeout, &priv->regs->counter_reload_val); + writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart); + /* + * Setting CLK1MHZ bit is just for compatibility with ast2400 part. + * On ast2500 watchdog timer clock is fixed at 1MHz and the bit is + * read-only + */ + setbits_le32(&priv->regs->ctrl, + WDT_CTRL_EN | WDT_CTRL_RESET | WDT_CTRL_CLK1MHZ); + + return 0; +} + +static int ast_wdt_stop(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + clrbits_le32(&priv->regs->ctrl, WDT_CTRL_EN); + + return 0; +} + +static int ast_wdt_reset(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_COUNTER_RESTART_VAL, &priv->regs->counter_restart); + + return 0; +} + +static int ast_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + int ret; + + ret = ast_wdt_start(dev, 1, flags); + if (ret) + return ret; + + while (readl(&priv->regs->ctrl) & WDT_CTRL_EN) + ; + + return ast_wdt_stop(dev); +} + +static int ast_wdt_ofdata_to_platdata(struct udevice *dev) +{ + struct ast_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = dev_get_addr_ptr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + return 0; +} + +static const struct wdt_ops ast_wdt_ops = { + .start = ast_wdt_start, + .reset = ast_wdt_reset, + .stop = ast_wdt_stop, + .expire_now = ast_wdt_expire_now, +}; + +static const struct udevice_id ast_wdt_ids[] = { + { .compatible = "aspeed,wdt", .data = WDT_AST2500 }, + { .compatible = "aspeed,ast2500-wdt", .data = WDT_AST2500 }, + { .compatible = "aspeed,ast2400-wdt", .data = WDT_AST2400 }, + {} +}; + +static int ast_wdt_probe(struct udevice *dev) +{ + debug("%s() wdt%u\n", __func__, dev->seq); + ast_wdt_stop(dev); + + return 0; +} + +U_BOOT_DRIVER(ast_wdt) = { + .name = "ast_wdt", + .id = UCLASS_WDT, + .of_match = ast_wdt_ids, + .probe = ast_wdt_probe, + .priv_auto_alloc_size = sizeof(struct ast_wdt_priv), + .ofdata_to_platdata = ast_wdt_ofdata_to_platdata, + .ops = &ast_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c deleted file mode 100644 index 6a8db59fdf..0000000000 --- a/drivers/watchdog/bfin_wdt.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * watchdog.c - driver for Blackfin on-chip watchdog - * - * Copyright (c) 2007-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <watchdog.h> -#include <asm/blackfin.h> -#include <asm/clock.h> -#include <asm/mach-common/bits/watchdog.h> - -void hw_watchdog_reset(void) -{ - bfin_write_WDOG_STAT(0); -} - -void hw_watchdog_init(void) -{ - bfin_write_WDOG_CTL(WDDIS); - SSYNC(); - bfin_write_WDOG_CNT(CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000 * get_sclk()); - hw_watchdog_reset(); - bfin_write_WDOG_CTL(WDEN); -} diff --git a/drivers/watchdog/sandbox_wdt.c b/drivers/watchdog/sandbox_wdt.c new file mode 100644 index 0000000000..02b57f3986 --- /dev/null +++ b/drivers/watchdog/sandbox_wdt.c @@ -0,0 +1,66 @@ +/* + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <asm/state.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct sandbox_state *state = state_get_current(); + + state->wdt.counter = timeout; + state->wdt.running = true; + + return 0; +} + +static int sandbox_wdt_stop(struct udevice *dev) +{ + struct sandbox_state *state = state_get_current(); + + state->wdt.running = false; + + return 0; +} + +static int sandbox_wdt_reset(struct udevice *dev) +{ + struct sandbox_state *state = state_get_current(); + + state->wdt.reset_count++; + + return 0; +} + +static int sandbox_wdt_expire_now(struct udevice *dev, ulong flags) +{ + sandbox_wdt_start(dev, 1, flags); + + return 0; +} + +static const struct wdt_ops sandbox_wdt_ops = { + .start = sandbox_wdt_start, + .reset = sandbox_wdt_reset, + .stop = sandbox_wdt_stop, + .expire_now = sandbox_wdt_expire_now, +}; + +static const struct udevice_id sandbox_wdt_ids[] = { + { .compatible = "sandbox,wdt" }, + {} +}; + +U_BOOT_DRIVER(wdt_sandbox) = { + .name = "wdt_sandbox", + .id = UCLASS_WDT, + .of_match = sandbox_wdt_ids, + .ops = &sandbox_wdt_ops, +}; diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c new file mode 100644 index 0000000000..ab8a64c354 --- /dev/null +++ b/drivers/watchdog/wdt-uclass.c @@ -0,0 +1,72 @@ +/* + * Copyright 2017 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <dm/device-internal.h> +#include <dm/lists.h> + +DECLARE_GLOBAL_DATA_PTR; + +int wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + const struct wdt_ops *ops = device_get_ops(dev); + + if (!ops->start) + return -ENOSYS; + + return ops->start(dev, timeout, flags); +} + +int wdt_stop(struct udevice *dev) +{ + const struct wdt_ops *ops = device_get_ops(dev); + + if (!ops->stop) + return -ENOSYS; + + return ops->stop(dev); +} + +int wdt_reset(struct udevice *dev) +{ + const struct wdt_ops *ops = device_get_ops(dev); + + if (!ops->reset) + return -ENOSYS; + + return ops->reset(dev); +} + +int wdt_expire_now(struct udevice *dev, ulong flags) +{ + int ret = 0; + const struct wdt_ops *ops; + + debug("WDT Resettting: %lu\n", flags); + ops = device_get_ops(dev); + if (ops->expire_now) { + return ops->expire_now(dev, flags); + } else { + if (!ops->start) + return -ENOSYS; + + ret = ops->start(dev, 1, flags); + if (ret < 0) + return ret; + + hang(); + } + + return ret; +} + +UCLASS_DRIVER(wdt) = { + .id = UCLASS_WDT, + .name = "wdt", +}; |