diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2014-10-14 15:39:27 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2014-10-14 15:39:27 +0200 |
commit | 4181f1b45cdbac89f2f626a50ce59aa9c4fdf8dd (patch) | |
tree | 3bb7b8623e3caeaa0153b18bd8c9a5594330d4f9 /drivers | |
parent | 673ed5cf1f142b0e01959fa1e086ec7fdec4a9ae (diff) | |
parent | c43fd23cf619856b0763a64a6a3bcf3663058c49 (diff) |
Merge tag 'v2014.10' into 2014.10-toradex-next
Prepare v2014.10
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/ahci.c | 1 | ||||
-rw-r--r-- | drivers/mmc/s5p_sdhci.c | 2 | ||||
-rw-r--r-- | drivers/mtd/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 42 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/denali.c | 12 | ||||
-rw-r--r-- | drivers/mtd/nand/denali_spl.c | 231 | ||||
-rw-r--r-- | drivers/mtd/nand/vf610_nfc.c | 724 | ||||
-rw-r--r-- | drivers/net/macb.c | 25 | ||||
-rw-r--r-- | drivers/power/axp152.c | 2 | ||||
-rw-r--r-- | drivers/power/pmic/Makefile | 3 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_tps65090_ec.c | 218 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/serial-uclass.c | 2 | ||||
-rw-r--r-- | drivers/serial/serial.c | 2 | ||||
-rw-r--r-- | drivers/serial/serial_uniphier.c | 204 | ||||
-rw-r--r-- | drivers/usb/host/ehci-mx6.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ehci-mxs.c | 16 |
18 files changed, 1465 insertions, 27 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index dce99adc6b..a93a8e1c04 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -229,7 +229,6 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) * already be on in the command register. */ cmd = readl(port_mmio + PORT_CMD); - cmd |= PORT_CMD_FIS_RX; cmd |= PORT_CMD_SPIN_UP; writel_with_flush(cmd, port_mmio + PORT_CMD); diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 2ff0ec2a42..637dd972a5 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -14,9 +14,7 @@ #include <asm/arch/mmc.h> #include <asm/arch/clk.h> #include <errno.h> -#ifdef CONFIG_OF_CONTROL #include <asm/arch/pinmux.h> -#endif static char *S5P_NAME = "SAMSUNG SDHCI"; static void s5p_sdhci_set_control_reg(struct sdhci_host *host) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index e69de29bb2..415ab4eba9 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -0,0 +1 @@ +source "drivers/mtd/nand/Kconfig" diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig new file mode 100644 index 0000000000..75c2c065c8 --- /dev/null +++ b/drivers/mtd/nand/Kconfig @@ -0,0 +1,42 @@ +menu "NAND Device Support" + +if !SPL_BUILD + +config NAND_DENALI + bool "Support Denali NAND controller" + help + Enable support for the Denali NAND controller. + +config SYS_NAND_DENALI_64BIT + bool "Use 64-bit variant of Denali NAND controller" + depends on NAND_DENALI + help + The Denali NAND controller IP has some variations in terms of + the bus interface. The DMA setup sequence is completely differenct + between 32bit / 64bit AXI bus variants. + + If your Denali NAND controller is the 64-bit variant, say Y. + Otherwise (32 bit), say N. + +config NAND_DENALI_SPARE_AREA_SKIP_BYTES + int "Number of bytes skipped in OOB area" + depends on NAND_DENALI + range 0 63 + help + This option specifies the number of bytes to skip from the beginning + of OOB area before last ECC sector data starts. This is potentially + used to preserve the bad block marker in the OOB area. + +endif + +if SPL_BUILD + +config SPL_NAND_DENALI + bool "Support Denali NAND controller for SPL" + help + This is a small implementation of the Denali NAND controller + for use on SPL. + +endif + +endmenu diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index f298f8434a..1f02bfc35f 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -12,6 +12,7 @@ NORMAL_DRIVERS=y endif obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o +obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o @@ -52,6 +53,7 @@ obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o obj-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o +obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o obj-$(CONFIG_NAND_MXC) += mxc_nand.o obj-$(CONFIG_NAND_MXS) += mxs_nand.o obj-$(CONFIG_NAND_NDFC) += ndfc.o diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index ba3de1a635..308b7845f1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1059,9 +1059,8 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, addr = MODE_11 | BANK(denali->flash_bank); index_addr(denali, addr | 0, cmd); break; - case NAND_CMD_PARAM: - clear_interrupts(denali); case NAND_CMD_READID: + case NAND_CMD_PARAM: reset_buf(denali); /* sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips @@ -1070,6 +1069,15 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, addr = MODE_11 | BANK(denali->flash_bank); index_addr(denali, addr | 0, cmd); index_addr(denali, addr | 1, col & 0xFF); + if (cmd == NAND_CMD_PARAM) + udelay(50); + break; + case NAND_CMD_RNDOUT: + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, cmd); + index_addr(denali, addr | 1, col & 0xFF); + index_addr(denali, addr | 1, col >> 8); + index_addr(denali, addr | 0, NAND_CMD_RNDOUTSTART); break; case NAND_CMD_READ0: case NAND_CMD_SEQIN: diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c new file mode 100644 index 0000000000..65fdde8a65 --- /dev/null +++ b/drivers/mtd/nand/denali_spl.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2014 Panasonic Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/unaligned.h> +#include <linux/mtd/nand.h> +#include "denali.h" + +#define SPARE_ACCESS 0x41 +#define MAIN_ACCESS 0x42 +#define PIPELINE_ACCESS 0x2000 + +#define BANK(x) ((x) << 24) + +static void __iomem *denali_flash_mem = + (void __iomem *)CONFIG_SYS_NAND_DATA_BASE; +static void __iomem *denali_flash_reg = + (void __iomem *)CONFIG_SYS_NAND_REGS_BASE; + +static const int flash_bank; +static uint8_t page_buffer[NAND_MAX_PAGESIZE]; +static int page_size, oob_size, pages_per_block; + +static void index_addr(uint32_t address, uint32_t data) +{ + writel(address, denali_flash_mem + INDEX_CTRL_REG); + writel(data, denali_flash_mem + INDEX_DATA_REG); +} + +static int wait_for_irq(uint32_t irq_mask) +{ + unsigned long timeout = 1000000; + uint32_t intr_status; + + do { + intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank)); + + if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) { + debug("Uncorrected ECC detected\n"); + return -EIO; + } + + if (intr_status & irq_mask) + break; + + udelay(1); + timeout--; + } while (timeout); + + if (!timeout) { + debug("Timeout with interrupt status %08x\n", intr_status); + return -EIO; + } + + return 0; +} + +static void read_data_from_flash_mem(uint8_t *buf, int len) +{ + int i; + uint32_t *buf32; + + /* transfer the data from the flash */ + buf32 = (uint32_t *)buf; + + /* + * Let's take care of unaligned access although it rarely happens. + * Avoid put_unaligned() for the normal use cases since it leads to + * a bit performance regression. + */ + if ((unsigned long)buf32 % 4) { + for (i = 0; i < len / 4; i++) + put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG), + buf32++); + } else { + for (i = 0; i < len / 4; i++) + *buf32++ = readl(denali_flash_mem + INDEX_DATA_REG); + } + + if (len % 4) { + u32 tmp; + + tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG)); + buf = (uint8_t *)buf32; + for (i = 0; i < len % 4; i++) { + *buf++ = tmp; + tmp >>= 8; + } + } +} + +int denali_send_pipeline_cmd(int page, int ecc_en, int access_type) +{ + uint32_t addr, cmd; + static uint32_t page_count = 1; + + writel(ecc_en, denali_flash_reg + ECC_ENABLE); + + /* clear all bits of intr_status. */ + writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank)); + + addr = BANK(flash_bank) | page; + + /* setup the acccess type */ + cmd = MODE_10 | addr; + index_addr(cmd, access_type); + + /* setup the pipeline command */ + index_addr(cmd, PIPELINE_ACCESS | page_count); + + cmd = MODE_01 | addr; + writel(cmd, denali_flash_mem + INDEX_CTRL_REG); + + return wait_for_irq(INTR_STATUS__LOAD_COMP); +} + +static int nand_read_oob(void *buf, int page) +{ + int ret; + + ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS); + if (ret < 0) + return ret; + + read_data_from_flash_mem(buf, oob_size); + + return 0; +} + +static int nand_read_page(void *buf, int page) +{ + int ret; + + ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS); + if (ret < 0) + return ret; + + read_data_from_flash_mem(buf, page_size); + + return 0; +} + +static int nand_block_isbad(int block) +{ + int ret; + + ret = nand_read_oob(page_buffer, block * pages_per_block); + if (ret < 0) + return ret; + + return page_buffer[CONFIG_SYS_NAND_BAD_BLOCK_POS] != 0xff; +} + +/* nand_init() - initialize data to make nand usable by SPL */ +void nand_init(void) +{ + /* access to main area */ + writel(0, denali_flash_reg + TRANSFER_SPARE_REG); + + /* + * These registers are expected to be already set by the hardware + * or earlier boot code. So we read these values out. + */ + page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE); + oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE); + pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK); +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{ + int block, page, column, readlen; + int ret; + int force_bad_block_check = 1; + + page = offs / page_size; + column = offs % page_size; + + block = page / pages_per_block; + page = page % pages_per_block; + + while (size) { + if (force_bad_block_check || page == 0) { + ret = nand_block_isbad(block); + if (ret < 0) + return ret; + + if (ret) { + block++; + continue; + } + } + + force_bad_block_check = 0; + + if (unlikely(column || size < page_size)) { + /* Partial page read */ + ret = nand_read_page(page_buffer, + block * pages_per_block + page); + if (ret < 0) + return ret; + + readlen = min(page_size - column, size); + memcpy(dst, page_buffer, readlen); + + column = 0; + } else { + ret = nand_read_page(dst, + block * pages_per_block + page); + if (ret < 0) + return ret; + + readlen = page_size; + } + + size -= readlen; + dst += readlen; + page++; + if (page == pages_per_block) { + block++; + page = 0; + } + } + + return 0; +} + +void nand_deselect(void) {} diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c new file mode 100644 index 0000000000..7feb3a7b1e --- /dev/null +++ b/drivers/mtd/nand/vf610_nfc.c @@ -0,0 +1,724 @@ +/* + * Copyright 2009-2014 Freescale Semiconductor, Inc. and others + * + * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver. + * Ported to U-Boot by Stefan Agner + * Based on RFC driver posted on Kernel Mailing list by Bill Pringlemeir + * Jason ported to M54418TWR and MVFA5. + * Authors: Stefan Agner <stefan.agner@toradex.com> + * Bill Pringlemeir <bpringlemeir@nbsps.com> + * Shaohui Xie <b21989@freescale.com> + * Jason Jin <Jason.jin@freescale.com> + * + * Based on original driver mpc5121_nfc.c. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Limitations: + * - Untested on MPC5125 and M54418. + * - DMA not used. + * - 2K pages or less. + * - Only 2K page w. 64+OOB and hardware ECC. + */ + +#include <common.h> +#include <malloc.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include <nand.h> +#include <errno.h> +#include <asm/io.h> + +/* Register Offsets */ +#define NFC_FLASH_CMD1 0x3F00 +#define NFC_FLASH_CMD2 0x3F04 +#define NFC_COL_ADDR 0x3F08 +#define NFC_ROW_ADDR 0x3F0c +#define NFC_ROW_ADDR_INC 0x3F14 +#define NFC_FLASH_STATUS1 0x3F18 +#define NFC_FLASH_STATUS2 0x3F1c +#define NFC_CACHE_SWAP 0x3F28 +#define NFC_SECTOR_SIZE 0x3F2c +#define NFC_FLASH_CONFIG 0x3F30 +#define NFC_IRQ_STATUS 0x3F38 + +/* Addresses for NFC MAIN RAM BUFFER areas */ +#define NFC_MAIN_AREA(n) ((n) * 0x1000) + +#define PAGE_2K 0x0800 +#define OOB_64 0x0040 + +/* + * NFC_CMD2[CODE] values. See section: + * - 31.4.7 Flash Command Code Description, Vybrid manual + * - 23.8.6 Flash Command Sequencer, MPC5125 manual + * + * Briefly these are bitmasks of controller cycles. + */ +#define READ_PAGE_CMD_CODE 0x7EE0 +#define PROGRAM_PAGE_CMD_CODE 0x7FC0 +#define ERASE_CMD_CODE 0x4EC0 +#define READ_ID_CMD_CODE 0x4804 +#define RESET_CMD_CODE 0x4040 +#define STATUS_READ_CMD_CODE 0x4068 + +/* NFC ECC mode define */ +#define ECC_BYPASS 0 +#define ECC_45_BYTE 6 + +/*** Register Mask and bit definitions */ + +/* NFC_FLASH_CMD1 Field */ +#define CMD_BYTE2_MASK 0xFF000000 +#define CMD_BYTE2_SHIFT 24 + +/* NFC_FLASH_CM2 Field */ +#define CMD_BYTE1_MASK 0xFF000000 +#define CMD_BYTE1_SHIFT 24 +#define CMD_CODE_MASK 0x00FFFF00 +#define CMD_CODE_SHIFT 8 +#define BUFNO_MASK 0x00000006 +#define BUFNO_SHIFT 1 +#define START_BIT (1<<0) + +/* NFC_COL_ADDR Field */ +#define COL_ADDR_MASK 0x0000FFFF +#define COL_ADDR_SHIFT 0 + +/* NFC_ROW_ADDR Field */ +#define ROW_ADDR_MASK 0x00FFFFFF +#define ROW_ADDR_SHIFT 0 +#define ROW_ADDR_CHIP_SEL_RB_MASK 0xF0000000 +#define ROW_ADDR_CHIP_SEL_RB_SHIFT 28 +#define ROW_ADDR_CHIP_SEL_MASK 0x0F000000 +#define ROW_ADDR_CHIP_SEL_SHIFT 24 + +/* NFC_FLASH_STATUS2 Field */ +#define STATUS_BYTE1_MASK 0x000000FF + +/* NFC_FLASH_CONFIG Field */ +#define CONFIG_ECC_SRAM_ADDR_MASK 0x7FC00000 +#define CONFIG_ECC_SRAM_ADDR_SHIFT 22 +#define CONFIG_ECC_SRAM_REQ_BIT (1<<21) +#define CONFIG_DMA_REQ_BIT (1<<20) +#define CONFIG_ECC_MODE_MASK 0x000E0000 +#define CONFIG_ECC_MODE_SHIFT 17 +#define CONFIG_FAST_FLASH_BIT (1<<16) +#define CONFIG_16BIT (1<<7) +#define CONFIG_BOOT_MODE_BIT (1<<6) +#define CONFIG_ADDR_AUTO_INCR_BIT (1<<5) +#define CONFIG_BUFNO_AUTO_INCR_BIT (1<<4) +#define CONFIG_PAGE_CNT_MASK 0xF +#define CONFIG_PAGE_CNT_SHIFT 0 + +/* NFC_IRQ_STATUS Field */ +#define IDLE_IRQ_BIT (1<<29) +#define IDLE_EN_BIT (1<<20) +#define CMD_DONE_CLEAR_BIT (1<<18) +#define IDLE_CLEAR_BIT (1<<17) + +#define NFC_TIMEOUT (1000) + +/* ECC status placed at end of buffers. */ +#define ECC_SRAM_ADDR ((PAGE_2K+256-8) >> 3) +#define ECC_STATUS_MASK 0x80 +#define ECC_ERR_COUNT 0x3F + +/* + * ECC status is stored at NFC_CFG[ECCADD] +4 for little-endian + * and +7 for big-endian SOC. + */ +#ifdef CONFIG_VF610 +#define ECC_OFFSET 4 +#else +#define ECC_OFFSET 7 +#endif + +struct vf610_nfc { + struct mtd_info *mtd; + struct nand_chip chip; + void __iomem *regs; + uint column; + int spareonly; + int page; + /* Status and ID are in alternate locations. */ + int alt_buf; +#define ALT_BUF_ID 1 +#define ALT_BUF_STAT 2 + struct clk *clk; +}; + +#define mtd_to_nfc(_mtd) \ + (struct vf610_nfc *)((struct nand_chip *)_mtd->priv)->priv + +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 11, + .len = 4, + .veroffs = 15, + .maxblocks = 4, + .pattern = mirror_pattern, +}; + +static struct nand_ecclayout vf610_nfc_ecc45 = { + .eccbytes = 45, + .eccpos = {19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 8, + .length = 11} } +}; + +static inline u32 vf610_nfc_read(struct mtd_info *mtd, uint reg) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + return readl(nfc->regs + reg); +} + +static inline void vf610_nfc_write(struct mtd_info *mtd, uint reg, u32 val) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + writel(val, nfc->regs + reg); +} + +static inline void vf610_nfc_set(struct mtd_info *mtd, uint reg, u32 bits) +{ + vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) | bits); +} + +static inline void vf610_nfc_clear(struct mtd_info *mtd, uint reg, u32 bits) +{ + vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) & ~bits); +} + +static inline void vf610_nfc_set_field(struct mtd_info *mtd, u32 reg, + u32 mask, u32 shift, u32 val) +{ + vf610_nfc_write(mtd, reg, + (vf610_nfc_read(mtd, reg) & (~mask)) | val << shift); +} + +static inline void vf610_nfc_memcpy(void *dst, const void *src, size_t n) +{ + /* + * Use this accessor for the interal SRAM buffers. On ARM we can + * treat the SRAM buffer as if its memory, hence use memcpy + */ + memcpy(dst, src, n); +} + +/* Clear flags for upcoming command */ +static inline void vf610_nfc_clear_status(void __iomem *regbase) +{ + void __iomem *reg = regbase + NFC_IRQ_STATUS; + u32 tmp = __raw_readl(reg); + tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT; + __raw_writel(tmp, reg); +} + +/* Wait for complete operation */ +static inline void vf610_nfc_done(struct mtd_info *mtd) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint start; + + /* + * Barrier is needed after this write. This write need + * to be done before reading the next register the first + * time. + * vf610_nfc_set implicates such a barrier by using writel + * to write to the register. + */ + vf610_nfc_set(mtd, NFC_FLASH_CMD2, START_BIT); + + start = get_timer(0); + + while (!(vf610_nfc_read(mtd, NFC_IRQ_STATUS) & IDLE_IRQ_BIT)) { + if (get_timer(start) > NFC_TIMEOUT) { + printf("Timeout while waiting for !BUSY.\n"); + return; + } + } + vf610_nfc_clear_status(nfc->regs); +} + +static u8 vf610_nfc_get_id(struct mtd_info *mtd, int col) +{ + u32 flash_id; + + if (col < 4) { + flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS1); + return (flash_id >> (3-col)*8) & 0xff; + } else { + flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS2); + return flash_id >> 24; + } +} + +static u8 vf610_nfc_get_status(struct mtd_info *mtd) +{ + return vf610_nfc_read(mtd, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK; +} + +/* Single command */ +static void vf610_nfc_send_command(void __iomem *regbase, u32 cmd_byte1, + u32 cmd_code) +{ + void __iomem *reg = regbase + NFC_FLASH_CMD2; + u32 tmp; + vf610_nfc_clear_status(regbase); + + tmp = __raw_readl(reg); + tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK); + tmp |= cmd_byte1 << CMD_BYTE1_SHIFT; + tmp |= cmd_code << CMD_CODE_SHIFT; + __raw_writel(tmp, reg); +} + +/* Two commands */ +static void vf610_nfc_send_commands(void __iomem *regbase, u32 cmd_byte1, + u32 cmd_byte2, u32 cmd_code) +{ + void __iomem *reg = regbase + NFC_FLASH_CMD1; + u32 tmp; + vf610_nfc_send_command(regbase, cmd_byte1, cmd_code); + + tmp = __raw_readl(reg); + tmp &= ~CMD_BYTE2_MASK; + tmp |= cmd_byte2 << CMD_BYTE2_SHIFT; + __raw_writel(tmp, reg); +} + +static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) +{ + if (column != -1) { + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + if (nfc->chip.options | NAND_BUSWIDTH_16) + column = column/2; + vf610_nfc_set_field(mtd, NFC_COL_ADDR, COL_ADDR_MASK, + COL_ADDR_SHIFT, column); + } + if (page != -1) + vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, page); +} + +/* Send command to NAND chip */ +static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, + int column, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + nfc->column = max(column, 0); + nfc->spareonly = 0; + nfc->alt_buf = 0; + + switch (command) { + case NAND_CMD_PAGEPROG: + nfc->page = -1; + vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN, + command, PROGRAM_PAGE_CMD_CODE); + vf610_nfc_addr_cycle(mtd, column, page); + break; + + case NAND_CMD_RESET: + vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE); + break; + /* + * NFC does not support sub-page reads and writes, + * so emulate them using full page transfers. + */ + case NAND_CMD_READOOB: + nfc->spareonly = 1; + case NAND_CMD_SEQIN: /* Pre-read for partial writes. */ + case NAND_CMD_READ0: + column = 0; + /* Already read? */ + if (nfc->page == page) + return; + nfc->page = page; + vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0, + NAND_CMD_READSTART, READ_PAGE_CMD_CODE); + vf610_nfc_addr_cycle(mtd, column, page); + break; + + case NAND_CMD_ERASE1: + if (nfc->page == page) + nfc->page = -1; + vf610_nfc_send_commands(nfc->regs, command, + NAND_CMD_ERASE2, ERASE_CMD_CODE); + vf610_nfc_addr_cycle(mtd, column, page); + break; + + case NAND_CMD_READID: + nfc->alt_buf = ALT_BUF_ID; + vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE); + break; + + case NAND_CMD_STATUS: + nfc->alt_buf = ALT_BUF_STAT; + vf610_nfc_send_command(nfc->regs, command, + STATUS_READ_CMD_CODE); + break; + default: + return; + } + + vf610_nfc_done(mtd); +} + +static inline void vf610_nfc_read_spare(struct mtd_info *mtd, void *buf, + int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + len = min(mtd->oobsize, (uint)len); + if (len > 0) + vf610_nfc_memcpy(buf, nfc->regs + mtd->writesize, len); +} + +/* Read data from NFC buffers */ +static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint c = nfc->column; + uint l; + + /* Handle main area */ + if (!nfc->spareonly) { + l = min((uint)len, mtd->writesize - c); + nfc->column += l; + + if (!nfc->alt_buf) + vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, + l); + else + if (nfc->alt_buf & ALT_BUF_ID) + *buf = vf610_nfc_get_id(mtd, c); + else + *buf = vf610_nfc_get_status(mtd); + + buf += l; + len -= l; + } + + /* Handle spare area access */ + if (len) { + nfc->column += len; + vf610_nfc_read_spare(mtd, buf, len); + } +} + +/* Write data to NFC buffers */ +static void vf610_nfc_write_buf(struct mtd_info *mtd, const u_char *buf, + int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint c = nfc->column; + uint l; + + l = min((uint)len, mtd->writesize + mtd->oobsize - c); + nfc->column += l; + vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l); +} + +/* Read byte from NFC buffers */ +static u8 vf610_nfc_read_byte(struct mtd_info *mtd) +{ + u8 tmp; + vf610_nfc_read_buf(mtd, &tmp, sizeof(tmp)); + return tmp; +} + +/* Read word from NFC buffers */ +static u16 vf610_nfc_read_word(struct mtd_info *mtd) +{ + u16 tmp; + vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); + return tmp; +} + +/* If not provided, upper layers apply a fixed delay. */ +static int vf610_nfc_dev_ready(struct mtd_info *mtd) +{ + /* NFC handles R/B internally; always ready. */ + return 1; +} + +/* + * This function supports Vybrid only (MPC5125 would have full RB and four CS) + */ +static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip) +{ +#ifdef CONFIG_VF610 + u32 tmp = vf610_nfc_read(mtd, NFC_ROW_ADDR); + tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); + tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; + + if (chip == 0) + tmp |= 1 << ROW_ADDR_CHIP_SEL_SHIFT; + else if (chip == 1) + tmp |= 2 << ROW_ADDR_CHIP_SEL_SHIFT; + + vf610_nfc_write(mtd, NFC_ROW_ADDR, tmp); +#endif +} + +/* Count the number of 0's in buff upto max_bits */ +static inline int count_written_bits(uint8_t *buff, int size, int max_bits) +{ + uint32_t *buff32 = (uint32_t *)buff; + int k, written_bits = 0; + + for (k = 0; k < (size / 4); k++) { + written_bits += hweight32(~buff32[k]); + if (written_bits > max_bits) + break; + } + + return written_bits; +} + +static inline int vf610_nfc_correct_data(struct mtd_info *mtd, u_char *dat) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + u8 ecc_status; + u8 ecc_count; + int flip; + + ecc_status = __raw_readb(nfc->regs + ECC_SRAM_ADDR * 8 + ECC_OFFSET); + ecc_count = ecc_status & ECC_ERR_COUNT; + if (!(ecc_status & ECC_STATUS_MASK)) + return ecc_count; + + /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ + flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count); + + /* ECC failed. */ + if (flip > ecc_count) { + nfc->page = -1; + return -1; + } + + /* Erased page. */ + memset(dat, 0xff, nfc->chip.ecc.size); + return 0; +} + + +static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int eccsize = chip->ecc.size; + int stat; + uint8_t *p = buf; + + + vf610_nfc_read_buf(mtd, p, eccsize); + + if (oob_required) + vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + + stat = vf610_nfc_correct_data(mtd, p); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + return 0; +} + +/* + * ECC will be calculated automatically + */ +static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + vf610_nfc_write_buf(mtd, buf, mtd->writesize); + if (oob_required) + vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +struct vf610_nfc_config { + int hardware_ecc; + int width; + int flash_bbt; +}; + +static int vf610_nfc_nand_init(int devnum, void __iomem *addr) +{ + struct mtd_info *mtd = &nand_info[devnum]; + struct nand_chip *chip; + struct vf610_nfc *nfc; + int err = 0; + int page_sz; + struct vf610_nfc_config cfg = { + .hardware_ecc = 1, +#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT + .width = 16, +#else + .width = 8, +#endif + .flash_bbt = 1, + }; + + nfc = malloc(sizeof(*nfc)); + if (!nfc) { + printf(KERN_ERR "%s: Memory exhausted!\n", __func__); + return -ENOMEM; + } + + chip = &nfc->chip; + nfc->regs = addr; + + mtd->priv = chip; + chip->priv = nfc; + + if (cfg.width == 16) { + chip->options |= NAND_BUSWIDTH_16; + vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); + } else { + chip->options &= ~NAND_BUSWIDTH_16; + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT); + } + + chip->dev_ready = vf610_nfc_dev_ready; + chip->cmdfunc = vf610_nfc_command; + chip->read_byte = vf610_nfc_read_byte; + chip->read_word = vf610_nfc_read_word; + chip->read_buf = vf610_nfc_read_buf; + chip->write_buf = vf610_nfc_write_buf; + chip->select_chip = vf610_nfc_select_chip; + + /* Bad block options. */ + if (cfg.flash_bbt) + chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_CREATE; + + /* Default to software ECC until flash ID. */ + vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, + CONFIG_ECC_MODE_MASK, + CONFIG_ECC_MODE_SHIFT, ECC_BYPASS); + + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; + + page_sz = PAGE_2K + OOB_64; + page_sz += cfg.width == 16 ? 1 : 0; + vf610_nfc_write(mtd, NFC_SECTOR_SIZE, page_sz); + + /* Set configuration register. */ + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT); + vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT); + vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT); + + /* Enable Idle IRQ */ + vf610_nfc_set(mtd, NFC_IRQ_STATUS, IDLE_EN_BIT); + + /* PAGE_CNT = 1 */ + vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, + CONFIG_PAGE_CNT_SHIFT, 1); + + /* Set ECC_STATUS offset */ + vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, + CONFIG_ECC_SRAM_ADDR_MASK, + CONFIG_ECC_SRAM_ADDR_SHIFT, ECC_SRAM_ADDR); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) { + err = -ENXIO; + goto error; + } + + chip->ecc.mode = NAND_ECC_SOFT; /* default */ + + page_sz = mtd->writesize + mtd->oobsize; + + /* Single buffer only, max 256 OOB minus ECC status */ + if (page_sz > PAGE_2K + 256 - 8) { + dev_err(nfc->dev, "Unsupported flash size\n"); + err = -ENXIO; + goto error; + } + page_sz += cfg.width == 16 ? 1 : 0; + vf610_nfc_write(mtd, NFC_SECTOR_SIZE, page_sz); + + if (cfg.hardware_ecc) { + if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { + dev_err(nfc->dev, "Unsupported flash with hwecc\n"); + err = -ENXIO; + goto error; + } + + chip->ecc.layout = &vf610_nfc_ecc45; + + /* propagate ecc.layout to mtd_info */ + mtd->ecclayout = chip->ecc.layout; + chip->ecc.read_page = vf610_nfc_read_page; + chip->ecc.write_page = vf610_nfc_write_page; + chip->ecc.mode = NAND_ECC_HW; + + chip->ecc.bytes = 45; + chip->ecc.size = PAGE_2K; + chip->ecc.strength = 24; + + /* set ECC mode to 45 bytes OOB with 24 bits correction */ + vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, + CONFIG_ECC_MODE_MASK, + CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE); + + /* Enable ECC_STATUS */ + vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT); + } + + /* second phase scan */ + err = nand_scan_tail(mtd); + if (err) + return err; + + err = nand_register(devnum); + if (err) + return err; + + return 0; + +error: + return err; +} + +void board_nand_init(void) +{ + int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE); + if (err) + printf("VF610 NAND init failed (err %d)\n", err); +} diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 01a94a4c4d..375c8a4454 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -479,31 +479,22 @@ static int macb_phy_init(struct macb_device *macb) /* First check for GMAC */ if (macb_is_gem(macb)) { lpa = macb_mdio_read(macb, MII_STAT1000); - if (lpa & (1 << 11)) { - speed = 1000; - duplex = 1; - } else { - if (lpa & (1 << 10)) { - speed = 1000; - duplex = 1; - } else { - speed = 0; - } - } - if (speed == 1000) { - printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n", + if (lpa & (LPA_1000FULL | LPA_1000HALF)) { + duplex = ((lpa & LPA_1000FULL) ? 1 : 0); + + printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", netdev->name, - speed, duplex ? "full" : "half", lpa); ncfgr = macb_readl(macb, NCFGR); - ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD)); - if (speed) - ncfgr |= GEM_BIT(GBE); + ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); + ncfgr |= GEM_BIT(GBE); + if (duplex) ncfgr |= MACB_BIT(FD); + macb_writel(macb, NCFGR, ncfgr); return 1; diff --git a/drivers/power/axp152.c b/drivers/power/axp152.c index fa4ea050a5..27c2c4c8da 100644 --- a/drivers/power/axp152.c +++ b/drivers/power/axp152.c @@ -62,7 +62,7 @@ int axp152_set_dcdc2(int mvolt) int axp152_set_dcdc3(int mvolt) { - u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 25); + u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 50); return axp152_write(AXP152_DCDC3_VOLTAGE, target); } diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index a472f61f88..e7b07ebab4 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,7 +11,8 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o -obj-$(CONFIG_POWER_TPS65090) += pmic_tps65090.o +obj-$(CONFIG_POWER_TPS65090_I2C) += pmic_tps65090.o +obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o diff --git a/drivers/power/pmic/pmic_tps65090_ec.c b/drivers/power/pmic/pmic_tps65090_ec.c new file mode 100644 index 0000000000..ac0d44fec8 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090_ec.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <cros_ec.h> +#include <errno.h> +#include <power/tps65090_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define TPS65090_ADDR 0x48 + +static struct tps65090 { + struct cros_ec_dev *dev; /* The CROS_EC device */ +} config; + +/* TPS65090 register addresses */ +enum { + REG_IRQ1 = 0, + REG_CG_CTRL0 = 4, + REG_CG_STATUS1 = 0xa, + REG_FET1_CTRL = 0x0f, + REG_FET2_CTRL, + REG_FET3_CTRL, + REG_FET4_CTRL, + REG_FET5_CTRL, + REG_FET6_CTRL, + REG_FET7_CTRL, + TPS65090_NUM_REGS, +}; + +enum { + IRQ1_VBATG = 1 << 3, + CG_CTRL0_ENC_MASK = 0x01, + + MAX_FET_NUM = 7, + MAX_CTRL_READ_TRIES = 5, + + /* TPS65090 FET_CTRL register values */ + FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ + FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ + FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ + FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ + FET_CTRL_ENFET = 1 << 0, /* Enable FET */ +}; + +/** + * tps65090_read - read a byte from tps6090 + * + * @param reg The register address to read from. + * @param val We'll return value value read here. + * @return 0 if ok; error if EC returns failure. + */ +static int tps65090_read(u32 reg, u8 *val) +{ + return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1, + val, 1, true); +} + +/** + * tps65090_write - write a byte to tps6090 + * + * @param reg The register address to write to. + * @param val The value to write. + * @return 0 if ok; error if EC returns failure. + */ +static int tps65090_write(u32 reg, u8 val) +{ + return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1, + &val, 1, false); +} + +/** + * Checks for a valid FET number + * + * @param fet_id FET number to check + * @return 0 if ok, -EINVAL if FET value is out of range + */ +static int tps65090_check_fet(unsigned int fet_id) +{ + if (fet_id == 0 || fet_id > MAX_FET_NUM) { + debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", + fet_id, MAX_FET_NUM); + return -EINVAL; + } + + return 0; +} + +/** + * Set the power state for a FET + * + * @param fet_id Fet number to set (1..MAX_FET_NUM) + * @param set 1 to power on FET, 0 to power off + * @return -EIO if we got a comms error, -EAGAIN if the FET failed to + * change state. If all is ok, returns 0. + */ +static int tps65090_fet_set(int fet_id, bool set) +{ + int retry; + u8 reg, value; + + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; + if (set) + value |= FET_CTRL_ENFET; + + if (tps65090_write(REG_FET1_CTRL + fet_id - 1, value)) + return -EIO; + + /* Try reading until we get a result */ + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { + if (tps65090_read(REG_FET1_CTRL + fet_id - 1, ®)) + return -EIO; + + /* Check that the fet went into the expected state */ + if (!!(reg & FET_CTRL_PGFET) == set) + return 0; + + /* If we got a timeout, there is no point in waiting longer */ + if (reg & FET_CTRL_TOFET) + break; + + mdelay(1); + } + + debug("FET %d: Power good should have set to %d but reg=%#02x\n", + fet_id, set, reg); + return -EAGAIN; +} + +int tps65090_fet_enable(unsigned int fet_id) +{ + ulong start; + int loops; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + start = get_timer(0); + for (loops = 0;; loops++) { + ret = tps65090_fet_set(fet_id, true); + if (!ret) + break; + + if (get_timer(start) > 100) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(fet_id, false); + } + + if (ret) { + debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + } else if (loops) { + debug("%s: FET%d powered on after %lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + } + /* + * Unfortunately, there are some conditions where the power + * good bit will be 0, but the fet still comes up. One such + * case occurs with the lcd backlight. We'll just return 0 here + * and assume that the fet will eventually come up. + */ + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + +int tps65090_fet_disable(unsigned int fet_id) +{ + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + ret = tps65090_fet_set(fet_id, false); + + return ret; +} + +int tps65090_fet_is_enabled(unsigned int fet_id) +{ + u8 reg = 0; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + ret = tps65090_read(REG_FET1_CTRL + fet_id - 1, ®); + if (ret) { + debug("fail to read FET%u_CTRL register over I2C", fet_id); + return -EIO; + } + + return reg & FET_CTRL_ENFET; +} + +int tps65090_init(void) +{ + puts("TPS65090 PMIC EC init\n"); + + config.dev = board_get_cros_ec_dev(); + if (!config.dev) { + debug("%s: no cros_ec device: cannot init tps65090\n", + __func__); + return -ENODEV; + } + + return 0; +} diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 853a8c6919..b4f299bb0e 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o obj-$(CONFIG_MXS_AUART) += mxs_auart.o obj-$(CONFIG_ARC_SERIAL) += serial_arc.o obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o +obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index fd010cac42..6dde4eaf47 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -198,7 +198,7 @@ static int serial_pre_remove(struct udevice *dev) #ifdef CONFIG_SYS_STDIO_DEREGISTER struct serial_dev_priv *upriv = dev->uclass_priv; - if (stdio_deregister_dev(upriv->sdev), 0) + if (stdio_deregister_dev(upriv->sdev, 0)) return -EPERM; #endif diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index bbe60af627..82fbbd92e2 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -157,6 +157,7 @@ serial_initfunc(sh_serial_initialize); serial_initfunc(arm_dcc_initialize); serial_initfunc(mxs_auart_initialize); serial_initfunc(arc_serial_initialize); +serial_initfunc(uniphier_serial_initialize); /** * serial_register() - Register serial driver with serial driver core @@ -250,6 +251,7 @@ void serial_initialize(void) arm_dcc_initialize(); mxs_auart_initialize(); arc_serial_initialize(); + uniphier_serial_initialize(); serial_assign(default_serial_console()->name); } diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c new file mode 100644 index 0000000000..f8c9d921e2 --- /dev/null +++ b/drivers/serial/serial_uniphier.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2012-2014 Panasonic Corporation + * Author: Masahiro Yamada <yamada.m@jp.panasonic.com> + * + * Based on serial_ns16550.c + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <serial.h> + +#define UART_REG(x) \ + u8 x; \ + u8 postpad_##x[3]; + +/* + * Note: Register map is slightly different from that of 16550. + */ +struct uniphier_serial { + UART_REG(rbr); /* 0x00 */ + UART_REG(ier); /* 0x04 */ + UART_REG(iir); /* 0x08 */ + UART_REG(fcr); /* 0x0c */ + u8 mcr; /* 0x10 */ + u8 lcr; + u16 __postpad; + UART_REG(lsr); /* 0x14 */ + UART_REG(msr); /* 0x18 */ + u32 __none1; + u32 __none2; + u16 dlr; + u16 __postpad2; +}; + +#define thr rbr + +/* + * These are the definitions for the Line Control Register + */ +#define UART_LCR_WLS_8 0x03 /* 8 bit character length */ + +/* + * These are the definitions for the Line Status Register + */ +#define UART_LSR_DR 0x01 /* Data ready */ +#define UART_LSR_THRE 0x20 /* Xmit holding register empty */ + +DECLARE_GLOBAL_DATA_PTR; + +static void uniphier_serial_init(struct uniphier_serial *port) +{ + const unsigned int mode_x_div = 16; + unsigned int divisor; + + writeb(UART_LCR_WLS_8, &port->lcr); + + divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK, + mode_x_div * gd->baudrate); + + writew(divisor, &port->dlr); +} + +static void uniphier_serial_setbrg(struct uniphier_serial *port) +{ + uniphier_serial_init(port); +} + +static int uniphier_serial_tstc(struct uniphier_serial *port) +{ + return (readb(&port->lsr) & UART_LSR_DR) != 0; +} + +static int uniphier_serial_getc(struct uniphier_serial *port) +{ + while (!uniphier_serial_tstc(port)) + ; + + return readb(&port->rbr); +} + +static void uniphier_serial_putc(struct uniphier_serial *port, const char c) +{ + if (c == '\n') + uniphier_serial_putc(port, '\r'); + + while (!(readb(&port->lsr) & UART_LSR_THRE)) + ; + + writeb(c, &port->thr); +} + +static struct uniphier_serial *serial_ports[4] = { +#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0 + (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0, +#else + NULL, +#endif +#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1 + (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1, +#else + NULL, +#endif +#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2 + (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2, +#else + NULL, +#endif +#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3 + (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3, +#else + NULL, +#endif +}; + +/* Multi serial device functions */ +#define DECLARE_ESERIAL_FUNCTIONS(port) \ + static int eserial##port##_init(void) \ + { \ + uniphier_serial_init(serial_ports[port]); \ + return 0 ; \ + } \ + static void eserial##port##_setbrg(void) \ + { \ + uniphier_serial_setbrg(serial_ports[port]); \ + } \ + static int eserial##port##_getc(void) \ + { \ + return uniphier_serial_getc(serial_ports[port]); \ + } \ + static int eserial##port##_tstc(void) \ + { \ + return uniphier_serial_tstc(serial_ports[port]); \ + } \ + static void eserial##port##_putc(const char c) \ + { \ + uniphier_serial_putc(serial_ports[port], c); \ + } + +/* Serial device descriptor */ +#define INIT_ESERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = eserial##port##_init, \ + .stop = NULL, \ + .setbrg = eserial##port##_setbrg, \ + .getc = eserial##port##_getc, \ + .tstc = eserial##port##_tstc, \ + .putc = eserial##port##_putc, \ + .puts = default_serial_puts, \ +} + +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) +DECLARE_ESERIAL_FUNCTIONS(0); +struct serial_device uniphier_serial0_device = + INIT_ESERIAL_STRUCTURE(0, "ttyS0"); +#endif +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) +DECLARE_ESERIAL_FUNCTIONS(1); +struct serial_device uniphier_serial1_device = + INIT_ESERIAL_STRUCTURE(1, "ttyS1"); +#endif +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) +DECLARE_ESERIAL_FUNCTIONS(2); +struct serial_device uniphier_serial2_device = + INIT_ESERIAL_STRUCTURE(2, "ttyS2"); +#endif +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) +DECLARE_ESERIAL_FUNCTIONS(3); +struct serial_device uniphier_serial3_device = + INIT_ESERIAL_STRUCTURE(3, "ttyS3"); +#endif + +__weak struct serial_device *default_serial_console(void) +{ +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) + return &uniphier_serial0_device; +#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) + return &uniphier_serial1_device; +#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) + return &uniphier_serial2_device; +#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) + return &uniphier_serial3_device; +#else +#error "No uniphier serial ports configured." +#endif +} + +void uniphier_serial_initialize(void) +{ +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) + serial_register(&uniphier_serial0_device); +#endif +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) + serial_register(&uniphier_serial1_device); +#endif +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) + serial_register(&uniphier_serial2_device); +#endif +#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) + serial_register(&uniphier_serial3_device); +#endif +} diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index c0a557b2ad..9ec5a0a539 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -174,7 +174,7 @@ struct usbnc_regs { static void usb_oc_config(int index) { - struct usbnc_regs *usbnc = (struct usbnc_regs *)(USBOH3_USB_BASE_ADDR + + struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + USB_OTHERREGS_OFFSET); void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]); u32 val; @@ -207,7 +207,7 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { enum usb_init_type type; - struct usb_ehci *ehci = (struct usb_ehci *)(USBOH3_USB_BASE_ADDR + + struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR + (0x200 * index)); if (index > 3) diff --git a/drivers/usb/host/ehci-mxs.c b/drivers/usb/host/ehci-mxs.c index 4d652b32db..6b8d969bb0 100644 --- a/drivers/usb/host/ehci-mxs.c +++ b/drivers/usb/host/ehci-mxs.c @@ -77,6 +77,16 @@ static int ehci_mxs_toggle_clock(const struct ehci_mxs_port *port, int enable) return 0; } +int __weak board_ehci_hcd_init(int port) +{ + return 0; +} + +int __weak board_ehci_hcd_exit(int port) +{ + return 0; +} + int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { @@ -90,6 +100,10 @@ int ehci_hcd_init(int index, enum usb_init_type init, return -EINVAL; } + ret = board_ehci_hcd_init(index); + if (ret) + return ret; + port = &mxs_port[index]; /* Reset the PHY block */ @@ -154,5 +168,7 @@ int ehci_hcd_stop(int index) /* Disable USB clock */ ret = ehci_mxs_toggle_clock(port, 0); + board_ehci_hcd_exit(index); + return ret; } |