diff options
Diffstat (limited to 'drivers')
30 files changed, 1020 insertions, 114 deletions
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 4e94378..8697da4 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc.o obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o obj-$(CONFIG_SATA_SIL) += sata_sil.o obj-$(CONFIG_IDE_SIL680) += sil680.o +obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o obj-$(CONFIG_SYSTEMACE) += systemace.o diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c new file mode 100644 index 0000000..73f4c4a --- /dev/null +++ b/drivers/block/sandbox.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <part.h> +#include <os.h> +#include <malloc.h> +#include <sandboxblockdev.h> +#include <asm/errno.h> + +static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES]; + +static struct host_block_dev *find_host_device(int dev) +{ + if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES) + return &host_devices[dev]; + + return NULL; +} + +static unsigned long host_block_read(int dev, unsigned long start, + lbaint_t blkcnt, void *buffer) +{ + struct host_block_dev *host_dev = find_host_device(dev); + + if (!host_dev) + return -1; + if (os_lseek(host_dev->fd, + start * host_dev->blk_dev.blksz, + OS_SEEK_SET) == -1) { + printf("ERROR: Invalid position\n"); + return -1; + } + ssize_t len = os_read(host_dev->fd, buffer, + blkcnt * host_dev->blk_dev.blksz); + if (len >= 0) + return len / host_dev->blk_dev.blksz; + return -1; +} + +static unsigned long host_block_write(int dev, unsigned long start, + lbaint_t blkcnt, const void *buffer) +{ + struct host_block_dev *host_dev = find_host_device(dev); + if (os_lseek(host_dev->fd, + start * host_dev->blk_dev.blksz, + OS_SEEK_SET) == -1) { + printf("ERROR: Invalid position\n"); + return -1; + } + ssize_t len = os_write(host_dev->fd, buffer, blkcnt * + host_dev->blk_dev.blksz); + if (len >= 0) + return len / host_dev->blk_dev.blksz; + return -1; +} + +int host_dev_bind(int dev, char *filename) +{ + struct host_block_dev *host_dev = find_host_device(dev); + + if (!host_dev) + return -1; + if (host_dev->blk_dev.priv) { + os_close(host_dev->fd); + host_dev->blk_dev.priv = NULL; + } + if (host_dev->filename) + free(host_dev->filename); + if (filename && *filename) { + host_dev->filename = strdup(filename); + } else { + host_dev->filename = NULL; + return 0; + } + + host_dev->fd = os_open(host_dev->filename, OS_O_RDWR); + if (host_dev->fd == -1) { + printf("Failed to access host backing file '%s'\n", + host_dev->filename); + return 1; + } + + block_dev_desc_t *blk_dev = &host_dev->blk_dev; + blk_dev->if_type = IF_TYPE_HOST; + blk_dev->priv = host_dev; + blk_dev->blksz = 512; + blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz; + blk_dev->block_read = host_block_read; + blk_dev->block_write = host_block_write; + blk_dev->dev = dev; + blk_dev->part_type = PART_TYPE_UNKNOWN; + init_part(blk_dev); + + return 0; +} + +int host_get_dev_err(int dev, block_dev_desc_t **blk_devp) +{ + struct host_block_dev *host_dev = find_host_device(dev); + + if (!host_dev) + return -ENODEV; + + if (!host_dev->blk_dev.priv) + return -ENOENT; + + *blk_devp = &host_dev->blk_dev; + return 0; +} + +block_dev_desc_t *host_get_dev(int dev) +{ + block_dev_desc_t *blk_dev; + + if (host_get_dev_err(dev, &blk_dev)) + return NULL; + + return blk_dev; +} diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 1eb92e5..07011e9 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -74,6 +74,11 @@ unsigned char *dfu_free_buf(void) return dfu_buf; } +unsigned long dfu_get_buf_size(void) +{ + return dfu_buf_size; +} + unsigned char *dfu_get_buf(void) { char *s; diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 1ed26ca..e793ed9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o obj-$(CONFIG_DWMMC) += dw_mmc.o obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o +obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o else diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 19d9b0b..4cec5aa 100644..100755 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -6,6 +6,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include <bouncebuf.h> #include <common.h> #include <malloc.h> #include <mmc.h> @@ -41,11 +42,13 @@ static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, } static void dwmci_prepare_data(struct dwmci_host *host, - struct mmc_data *data, struct dwmci_idmac *cur_idmac) + struct mmc_data *data, + struct dwmci_idmac *cur_idmac, + void *bounce_buffer) { unsigned long ctrl; unsigned int i = 0, flags, cnt, blk_cnt; - ulong data_start, data_end, start_addr; + ulong data_start, data_end; blk_cnt = data->blocks; @@ -55,11 +58,6 @@ static void dwmci_prepare_data(struct dwmci_host *host, data_start = (ulong)cur_idmac; dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); - if (data->flags == MMC_DATA_READ) - start_addr = (unsigned int)data->dest; - else - start_addr = (unsigned int)data->src; - do { flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; @@ -70,7 +68,7 @@ static void dwmci_prepare_data(struct dwmci_host *host, cnt = data->blocksize * 8; dwmci_set_idma_desc(cur_idmac, flags, cnt, - start_addr + (i * PAGE_SIZE)); + (u32)bounce_buffer + (i * PAGE_SIZE)); if (blk_cnt <= 8) break; @@ -117,6 +115,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, u32 retry = 10000; u32 mask, ctrl; ulong start = get_timer(0); + struct bounce_buffer bbstate; while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { if (get_timer(start) > timeout) { @@ -127,8 +126,19 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); - if (data) - dwmci_prepare_data(host, data, cur_idmac); + if (data) { + if (data->flags == MMC_DATA_READ) { + bounce_buffer_start(&bbstate, (void*)data->dest, + data->blocksize * + data->blocks, GEN_BB_WRITE); + } else { + bounce_buffer_start(&bbstate, (void*)data->src, + data->blocksize * + data->blocks, GEN_BB_READ); + } + dwmci_prepare_data(host, data, cur_idmac, + bbstate.bounce_buffer); + } dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); @@ -204,6 +214,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, ctrl = dwmci_readl(host, DWMCI_CTRL); ctrl &= ~(DWMCI_DMA_EN); dwmci_writel(host, DWMCI_CTRL, ctrl); + + bounce_buffer_stop(&bbstate); } udelay(100); @@ -336,9 +348,9 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) struct mmc *mmc; int err = 0; - mmc = malloc(sizeof(struct mmc)); + mmc = calloc(sizeof(struct mmc), 1); if (!mmc) { - printf("mmc malloc fail!\n"); + printf("mmc calloc fail!\n"); return -1; } diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..c6a1c23 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -877,6 +877,7 @@ static int mmc_startup(struct mmc *mmc) mmc->tran_speed = freq * mult; + mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); if (IS_SD(mmc)) @@ -907,6 +908,14 @@ static int mmc_startup(struct mmc *mmc) if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) mmc->write_bl_len = MMC_MAX_BLOCK_LEN; + if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { + cmd.cmdidx = MMC_CMD_SET_DSR; + cmd.cmdarg = (mmc->dsr & 0xffff) << 16; + cmd.resp_type = MMC_RSP_NONE; + if (mmc_send_cmd(mmc, &cmd, NULL)) + printf("MMC: SET_DSR failed\n"); + } + /* Select the card, and put it into Transfer Mode */ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ cmd.cmdidx = MMC_CMD_SELECT_CARD; @@ -1163,6 +1172,9 @@ static int mmc_send_if_cond(struct mmc *mmc) int mmc_register(struct mmc *mmc) { + /* Setup dsr related values */ + mmc->dsr_imp = 0; + mmc->dsr = 0xffffffff; /* Setup the universal parts of the block interface just once */ mmc->block_dev.if_type = IF_TYPE_MMC; mmc->block_dev.dev = cur_dev_num++; @@ -1280,6 +1292,12 @@ int mmc_init(struct mmc *mmc) return err; } +int mmc_set_dsr(struct mmc *mmc, u16 val) +{ + mmc->dsr = val; + return 0; +} + /* * CPU and board-specific MMC initializations. Aliased function * signals caller to move on diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 46ae9cb..1e86b92 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -24,7 +24,8 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printf("Reset 0x%x never completed.\n", (int)mask); + printf("%s: Reset 0x%x never completed.\n", + __func__, (int)mask); return; } timeout--; @@ -79,7 +80,8 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, do { stat = sdhci_readl(host, SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) { - printf("Error detected in status(0x%X)!\n", stat); + printf("%s: Error detected in status(0x%X)!\n", + __func__, stat); return -1; } if (stat & rdy) { @@ -102,7 +104,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, if (timeout-- > 0) udelay(10); else { - printf("Transfer data timeout\n"); + printf("%s: Transfer data timeout\n", __func__); return -1; } } while (!(stat & SDHCI_INT_DATA_END)); @@ -147,7 +149,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (time >= cmd_timeout) { - printf("MMC: %d busy ", mmc_dev); + printf("%s: MMC: %d busy ", __func__, mmc_dev); if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; printf("timeout increasing to: %u ms.\n", @@ -179,7 +181,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (data) flags |= SDHCI_CMD_DATA; - /*Set Transfer mode regarding to data flag*/ + /* Set Transfer mode regarding to data flag */ if (data != 0) { sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); mode = SDHCI_TRNS_BLK_CNT_EN; @@ -230,7 +232,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) return 0; else { - printf("Timeout for status update!\n"); + printf("%s: Timeout for status update!\n", __func__); return TIMEOUT; } } @@ -307,7 +309,8 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printf("Internal clock never stabilised.\n"); + printf("%s: Internal clock never stabilised.\n", + __func__); return -1; } timeout--; @@ -397,7 +400,8 @@ int sdhci_init(struct mmc *mmc) if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { aligned_buffer = memalign(8, 512*1024); if (!aligned_buffer) { - printf("Aligned buffer alloc failed!!!"); + printf("%s: Aligned buffer alloc failed!!!\n", + __func__); return -1; } } @@ -418,8 +422,8 @@ int sdhci_init(struct mmc *mmc) } /* Enable only interrupts served by the SD controller */ - sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK - , SDHCI_INT_ENABLE); + sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK, + SDHCI_INT_ENABLE); /* Mask all sdhci interrupt sources */ sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE); @@ -433,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc = malloc(sizeof(struct mmc)); if (!mmc) { - printf("mmc malloc fail!\n"); + printf("%s: mmc malloc fail!\n", __func__); return -1; } @@ -450,7 +454,8 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) caps = sdhci_readl(host, SDHCI_CAPABILITIES); #ifdef CONFIG_MMC_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { - printf("Your controller don't support sdma!!\n"); + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); return -1; } #endif @@ -467,7 +472,8 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc->f_max *= 1000000; } if (mmc->f_max == 0) { - printf("Hardware doesn't specify base clock frequency\n"); + printf("%s: Hardware doesn't specify base clock frequency\n", + __func__); return -1; } if (min_clk) diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c new file mode 100644 index 0000000..bc53a5d --- /dev/null +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2013 Altera Corporation <www.altera.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <dwmmc.h> +#include <asm/arch/dwmmc.h> +#include <asm/arch/clock_manager.h> +#include <asm/arch/system_manager.h> + +static const struct socfpga_clock_manager *clock_manager_base = + (void *)SOCFPGA_CLKMGR_ADDRESS; +static const struct socfpga_system_manager *system_manager_base = + (void *)SOCFPGA_SYSMGR_ADDRESS; + +static char *SOCFPGA_NAME = "SOCFPGA DWMMC"; + +static void socfpga_dwmci_clksel(struct dwmci_host *host) +{ + unsigned int drvsel; + unsigned int smplsel; + + /* Disable SDMMC clock. */ + clrbits_le32(&clock_manager_base->per_pll_en, + CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + + /* Configures drv_sel and smpl_sel */ + drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL; + smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL; + + debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel); + writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel), + &system_manager_base->sdmmcgrp_ctrl); + + debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__, + readl(&system_manager_base->sdmmcgrp_ctrl)); + + /* Enable SDMMC clock */ + setbits_le32(&clock_manager_base->per_pll_en, + CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); +} + +int socfpga_dwmmc_init(u32 regbase, int bus_width, int index) +{ + struct dwmci_host *host = NULL; + host = calloc(sizeof(struct dwmci_host), 1); + if (!host) { + printf("dwmci_host calloc fail!\n"); + return -1; + } + + host->name = SOCFPGA_NAME; + host->ioaddr = (void *)regbase; + host->buswidth = bus_width; + host->clksel = socfpga_dwmci_clksel; + host->dev_index = index; + /* fixed clock divide by 4 which due to the SDMMC wrapper */ + host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ; + host->fifoth_val = MSIZE(0x2) | + RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) | + TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2); + + return add_dwmci(host, host->bus_hz, 400000); +} + diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index e145cd1..02b149c 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -5,8 +5,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_CMD_NAND - ifdef CONFIG_SPL_BUILD ifdef CONFIG_SPL_NAND_DRIVERS @@ -69,4 +67,3 @@ obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o endif # drivers -endif # nand diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index eeaa7e8..b292826 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -315,7 +315,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, int page; struct nand_chip *chip = mtd->priv; - debug("nand_unlock%s: start: %08llx, length: %d!\n", + debug("nand_unlock%s: start: %08llx, length: %zd!\n", allexcept ? " (allexcept)" : "", start, length); /* select the NAND device */ diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 5e7e6b3..790d538 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -283,53 +283,55 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode) if (bch->ecc_scheme == OMAP_ECC_BCH8_CODE_HW) { wr_mode = BCH_WRAPMODE_1; - switch (bch->nibbles) { - case ECC_BCH4_NIBBLES: - unused_length = 3; - break; - case ECC_BCH8_NIBBLES: - unused_length = 2; - break; - case ECC_BCH16_NIBBLES: - unused_length = 0; - break; - } - - /* - * This is ecc_size_config for ELM mode. - * Here we are using different settings for read and write access and - * also depending on BCH strength. - */ - switch (mode) { - case NAND_ECC_WRITE: - /* write access only setup eccsize1 config */ - val = ((unused_length + bch->nibbles) << 22); - break; + switch (bch->nibbles) { + case ECC_BCH4_NIBBLES: + unused_length = 3; + break; + case ECC_BCH8_NIBBLES: + unused_length = 2; + break; + case ECC_BCH16_NIBBLES: + unused_length = 0; + break; + } - case NAND_ECC_READ: - default: /* - * by default eccsize0 selected for ecc1resultsize - * eccsize0 config. + * This is ecc_size_config for ELM mode. Here we are using + * different settings for read and write access and also + * depending on BCH strength. */ - val = (bch->nibbles << 12); - /* eccsize1 config */ - val |= (unused_length << 22); - break; - } + switch (mode) { + case NAND_ECC_WRITE: + /* write access only setup eccsize1 config */ + val = ((unused_length + bch->nibbles) << 22); + break; + + case NAND_ECC_READ: + default: + /* + * by default eccsize0 selected for ecc1resultsize + * eccsize0 config. + */ + val = (bch->nibbles << 12); + /* eccsize1 config */ + val |= (unused_length << 22); + break; + } } else { - /* - * This ecc_size_config setting is for BCH sw library. - * - * Note: we only support BCH8 currently with BCH sw library! - * Should be really easy to adobt to BCH4, however some omap3 have - * flaws with BCH4. - * - * Here we are using wrapping mode 6 both for reading and writing, with: - * size0 = 0 (no additional protected byte in spare area) - * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) - */ - val = (32 << 22) | (0 << 12); + /* + * This ecc_size_config setting is for BCH sw library. + * + * Note: we only support BCH8 currently with BCH sw library! + * Should be really easy to adobt to BCH4, however some omap3 + * have flaws with BCH4. + * + * Here we are using wrapping mode 6 both for reading and + * writing, with: + * size0 = 0 (no additional protected byte in spare area) + * size1 = 32 (skip 32 nibbles = 16 bytes per sector in + * spare area) + */ + val = (32 << 22) | (0 << 12); } /* ecc size configuration */ writel(val, &gpmc_cfg->ecc_size_config); @@ -761,7 +763,7 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd) static int omap_select_ecc_scheme(struct nand_chip *nand, enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { struct nand_bch_priv *bch = nand->priv; - struct nand_ecclayout *ecclayout = nand->ecc.layout; + struct nand_ecclayout *ecclayout = &omap_ecclayout; int eccsteps = pagesize / SECTOR_BYTES; int i; @@ -774,7 +776,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, bch_priv.type = 0; nand->ecc.mode = NAND_ECC_SOFT; nand->ecc.layout = NULL; - nand->ecc.size = pagesize; + nand->ecc.size = 0; bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW; break; @@ -789,6 +791,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, bch_priv.control = NULL; bch_priv.type = 0; /* populate ecc specific fields */ + memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; nand->ecc.strength = 1; nand->ecc.size = SECTOR_BYTES; @@ -798,8 +801,12 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, nand->ecc.calculate = omap_calculate_ecc; /* define ecc-layout */ ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - for (i = 0; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++) { + if (nand->options & NAND_BUSWIDTH_16) + ecclayout->eccpos[i] = i + 2; + else + ecclayout->eccpos[i] = i + 1; + } ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; @@ -823,6 +830,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, } bch_priv.type = ECC_BCH8; /* populate ecc specific fields */ + memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; nand->ecc.strength = 8; nand->ecc.size = SECTOR_BYTES; @@ -865,6 +873,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, elm_init(); bch_priv.type = ECC_BCH8; /* populate ecc specific fields */ + memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; nand->ecc.strength = 8; nand->ecc.size = SECTOR_BYTES; @@ -891,6 +900,11 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, debug("nand: error: ecc scheme not enabled or supported\n"); return -EINVAL; } + + /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */ + if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW) + nand->ecc.layout = ecclayout; + return 0; } diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 979e4af..e33e8d3 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -91,7 +91,13 @@ static struct nand_ecclayout onenand_oob_32 = { .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} } }; -static const unsigned char ffchars[] = { +/* + * Warning! This array is used with the memcpy_16() function, thus + * it must be aligned to 2 bytes. GCC can make this array unaligned + * as the array is made of unsigned char, which memcpy16() doesn't + * like and will cause unaligned access. + */ +static const unsigned char __aligned(2) ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 108665f..e316a69 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -273,9 +273,15 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, /* Handle memory-mapped SPI */ if (flash->memory_map) { + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); memcpy(data, flash->memory_map + offset, len); spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); + spi_release_bus(flash->spi); return 0; } diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index c1eb754..b863a98 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -60,6 +60,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ + {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0}, {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, @@ -67,7 +68,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, - {"MX25L51235F", 0xc2201A, 0x0, 64 * 1024, 1024, 0}, + {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0}, {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile index e1f3a24..56c2823 100644 --- a/drivers/mtd/ubi/Makefile +++ b/drivers/mtd/ubi/Makefile @@ -5,9 +5,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_CMD_UBI obj-y += build.o vtbl.o vmt.o upd.o kapi.o eba.o io.o wl.o scan.o crc32.o - obj-y += misc.o obj-y += debug.o -endif diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c index cd787f4..74c72d3f 100644 --- a/drivers/net/fm/init.c +++ b/drivers/net/fm/init.c @@ -276,13 +276,64 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) "status", "disabled", strlen("disabled") + 1, 1); } +#ifdef CONFIG_SYS_FMAN_V3 +static int ft_fixup_xgec(void *blob, struct fm_eth_info *info) +{ + int off, i, ci; +#define FM1_10GEC3_RX_PORT_ADDR (CONFIG_SYS_CCSRBAR_PHYS + 0x488000) +#define FM1_10GEC3_TX_PORT_ADDR (CONFIG_SYS_CCSRBAR_PHYS + 0x4a8000) +#define FM1_10GEC3_MAC_ADDR (CONFIG_SYS_CCSRBAR_PHYS + 0x4e0000) + + if ((info->port == FM1_10GEC3) || (info->port == FM1_10GEC4)) { + ci = (info->port == FM1_10GEC3) ? 2 : 3; + i = (info->port == FM1_10GEC3) ? 0 : 1; + + off = fdt_node_offset_by_compat_reg(blob, "fsl,fman-port-1g-rx", + FM1_10GEC3_RX_PORT_ADDR + + i * 0x1000); + if (off > 0) { + fdt_setprop(blob, off, "cell-index", &ci, sizeof(int)); + fdt_setprop(blob, off, "compatible", + "fsl,fman-port-10g-rx", 20); + } else { + goto err; + } + + off = fdt_node_offset_by_compat_reg(blob, "fsl,fman-port-1g-tx", + FM1_10GEC3_TX_PORT_ADDR + + i * 0x1000); + if (off > 0) { + fdt_setprop(blob, off, "cell-index", &ci, sizeof(int)); + fdt_setprop(blob, off, "compatible", + "fsl,fman-port-10g-tx", 20); + } else { + goto err; + } + + off = fdt_node_offset_by_compat_reg(blob, "fsl,fman-memac", + FM1_10GEC3_MAC_ADDR + + i * 0x2000); + if (off > 0) + fdt_setprop(blob, off, "cell-index", &ci, sizeof(int)); + else + goto err; + } + return 0; +err: + printf("WARNING: Fail to find the node\n"); + return -1; +} +#endif + void fdt_fixup_fman_ethernet(void *blob) { int i; #ifdef CONFIG_SYS_FMAN_V3 - for (i = 0; i < ARRAY_SIZE(fm_info); i++) + for (i = 0; i < ARRAY_SIZE(fm_info); i++) { ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac"); + ft_fixup_xgec(blob, &fm_info[i]); + } #else for (i = 0; i < ARRAY_SIZE(fm_info); i++) { if (fm_info[i].type == FM_ETH_1G_E) diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 8aa7109..331c07c 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -287,7 +287,9 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { #if defined(CONFIG_CPU_SH7763) || defined(CONFIG_CPU_SH7734) #define SH_ETH_TYPE_GETHER #define BASE_IO_ADDR 0xfee00000 -#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) +#elif defined(CONFIG_CPU_SH7757) || \ + defined(CONFIG_CPU_SH7752) || \ + defined(CONFIG_CPU_SH7753) #if defined(CONFIG_SH_ETHER_USE_GETHER) #define SH_ETH_TYPE_GETHER #define BASE_IO_ADDR 0xfee00000 @@ -356,7 +358,9 @@ enum DMAC_T_BIT { /* GECMR */ enum GECMR_BIT { -#if defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) +#if defined(CONFIG_CPU_SH7757) || \ + defined(CONFIG_CPU_SH7752) || \ + defined(CONFIG_CPU_SH7753) GECMR_1000B = 0x20, GECMR_100B = 0x01, GECMR_10B = 0x00, #else GECMR_1000B = 0x01, GECMR_100B = 0x04, GECMR_10B = 0x00, diff --git a/drivers/serial/lpc32xx_hsuart.c b/drivers/serial/lpc32xx_hsuart.c index 9c7c621..c8926a8 100644 --- a/drivers/serial/lpc32xx_hsuart.c +++ b/drivers/serial/lpc32xx_hsuart.c @@ -38,6 +38,9 @@ static int lpc32xx_serial_getc(void) static void lpc32xx_serial_putc(const char c) { + if (c == '\n') + serial_putc('\r'); + writel(c, &hsuart->tx); /* Wait for character to be sent */ diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index 556b868..f5e9854 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -143,7 +143,9 @@ struct uart_port { #elif defined(CONFIG_H8S2678) # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define H8300_SCI_DR(ch) (*(volatile char *)(P1DR + h8300_sci_pins[ch].port)) -#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) +#elif defined(CONFIG_CPU_SH7757) || \ + defined(CONFIG_CPU_SH7752) || \ + defined(CONFIG_CPU_SH7753) # define SCSPTR0 0xfe4b0020 # define SCSPTR1 0xfe4b0020 # define SCSPTR2 0xfe4b0020 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index ed4ecd7..d5a7143 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o obj-$(CONFIG_SOFT_SPI) += soft_spi.o obj-$(CONFIG_SH_SPI) += sh_spi.o +obj-$(CONFIG_SH_QSPI) += sh_qspi.o obj-$(CONFIG_FSL_ESPI) += fsl_espi.o obj-$(CONFIG_FDT_SPI) += fdt_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c new file mode 100644 index 0000000..edeb42d --- /dev/null +++ b/drivers/spi/sh_qspi.c @@ -0,0 +1,277 @@ +/* + * SH QSPI (Quad SPI) driver + * + * Copyright (C) 2013 Renesas Electronics Corporation + * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> + +/* SH QSPI register bit masks <REG>_<BIT> */ +#define SPCR_MSTR 0x08 +#define SPCR_SPE 0x40 +#define SPSR_SPRFF 0x80 +#define SPSR_SPTEF 0x20 +#define SPPCR_IO3FV 0x04 +#define SPPCR_IO2FV 0x02 +#define SPPCR_IO1FV 0x01 +#define SPBDCR_RXBC0 (1 << 0) +#define SPCMD_SCKDEN (1 << 15) +#define SPCMD_SLNDEN (1 << 14) +#define SPCMD_SPNDEN (1 << 13) +#define SPCMD_SSLKP (1 << 7) +#define SPCMD_BRDV0 (1 << 2) +#define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \ + SPCMD_SPNDEN | SPCMD_SSLKP | \ + SPCMD_BRDV0 +#define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \ + SPCMD_BRDV0 +#define SPBFCR_TXRST (1 << 7) +#define SPBFCR_RXRST (1 << 6) + +/* SH QSPI register set */ +struct sh_qspi_regs { + unsigned char spcr; + unsigned char sslp; + unsigned char sppcr; + unsigned char spsr; + unsigned long spdr; + unsigned char spscr; + unsigned char spssr; + unsigned char spbr; + unsigned char spdcr; + unsigned char spckd; + unsigned char sslnd; + unsigned char spnd; + unsigned char dummy0; + unsigned short spcmd0; + unsigned short spcmd1; + unsigned short spcmd2; + unsigned short spcmd3; + unsigned char spbfcr; + unsigned char dummy1; + unsigned short spbdcr; + unsigned long spbmul0; + unsigned long spbmul1; + unsigned long spbmul2; + unsigned long spbmul3; +}; + +struct sh_qspi_slave { + struct spi_slave slave; + struct sh_qspi_regs *regs; +}; + +static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave) +{ + return container_of(slave, struct sh_qspi_slave, slave); +} + +static void sh_qspi_init(struct sh_qspi_slave *ss) +{ + /* QSPI initialize */ + /* Set master mode only */ + writeb(SPCR_MSTR, &ss->regs->spcr); + + /* Set SSL signal level */ + writeb(0x00, &ss->regs->sslp); + + /* Set MOSI signal value when transfer is in idle state */ + writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr); + + /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ + writeb(0x01, &ss->regs->spbr); + + /* Disable Dummy Data Transmission */ + writeb(0x00, &ss->regs->spdcr); + + /* Set clock delay value */ + writeb(0x00, &ss->regs->spckd); + + /* Set SSL negation delay value */ + writeb(0x00, &ss->regs->sslnd); + + /* Set next-access delay value */ + writeb(0x00, &ss->regs->spnd); + + /* Set equence command */ + writew(SPCMD_INIT2, &ss->regs->spcmd0); + + /* Reset transfer and receive Buffer */ + setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); + + /* Clear transfer and receive Buffer control bit */ + clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); + + /* Set equence control method. Use equence0 only */ + writeb(0x00, &ss->regs->spscr); + + /* Enable SPI function */ + setbits_8(&ss->regs->spcr, SPCR_SPE); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return 1; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct sh_qspi_slave *ss = to_sh_qspi(slave); + + /* Set master mode only */ + writeb(SPCR_MSTR, &ss->regs->spcr); + + /* Set command */ + writew(SPCMD_INIT1, &ss->regs->spcmd0); + + /* Reset transfer and receive Buffer */ + setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); + + /* Clear transfer and receive Buffer control bit */ + clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); + + /* Set equence control method. Use equence0 only */ + writeb(0x00, &ss->regs->spscr); + + /* Enable SPI function */ + setbits_8(&ss->regs->spcr, SPCR_SPE); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct sh_qspi_slave *ss = to_sh_qspi(slave); + + /* Disable SPI Function */ + clrbits_8(&ss->regs->spcr, SPCR_SPE); +} + +void spi_init(void) +{ + /* nothing to do */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct sh_qspi_slave *ss; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs); + if (!ss) { + printf("SPI_error: Fail to allocate sh_qspi_slave\n"); + return NULL; + } + + ss->regs = (struct sh_qspi_regs *)CONFIG_SH_QSPI_BASE; + + /* Init SH QSPI */ + sh_qspi_init(ss); + + return &ss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct sh_qspi_slave *spi = to_sh_qspi(slave); + + free(spi); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct sh_qspi_slave *ss = to_sh_qspi(slave); + unsigned long nbyte; + int ret = 0; + unsigned char dtdata = 0, drdata; + unsigned char *tdata = &dtdata, *rdata = &drdata; + unsigned long *spbmul0 = &ss->regs->spbmul0; + + if (dout == NULL && din == NULL) { + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + return 0; + } + + if (bitlen % 8) { + printf("%s: bitlen is not 8bit alined %d", __func__, bitlen); + return 1; + } + + nbyte = bitlen / 8; + + if (flags & SPI_XFER_BEGIN) { + spi_cs_activate(slave); + + /* Set 1048576 byte */ + writel(0x100000, spbmul0); + } + + if (flags & SPI_XFER_END) + writel(nbyte, spbmul0); + + if (dout != NULL) + tdata = (unsigned char *)dout; + + if (din != NULL) + rdata = din; + + while (nbyte > 0) { + while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) { + if (ctrlc()) { + puts("abort\n"); + return 1; + } + udelay(10); + } + + writeb(*tdata, (unsigned char *)(&ss->regs->spdr)); + + while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) { + if (ctrlc()) { + puts("abort\n"); + return 1; + } + udelay(1); + } + + while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) { + if (ctrlc()) { + puts("abort\n"); + return 1; + } + udelay(10); + } + + *rdata = readb((unsigned char *)(&ss->regs->spdr)); + + if (dout != NULL) + tdata++; + if (din != NULL) + rdata++; + + nbyte--; + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return ret; +} diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c index 4d2af48..810fa47 100644 --- a/drivers/spi/tegra114_spi.c +++ b/drivers/spi/tegra114_spi.c @@ -289,9 +289,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, reg = readl(®s->fifo_status); writel(reg, ®s->fifo_status); - /* clear ready bit */ - setbits_le32(®s->xfer_status, SPI_XFER_STS_RDY); - clrsetbits_le32(®s->command1, SPI_CMD1_CS_SW_VAL, SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE | (slave->cs << SPI_CMD1_CS_SEL_SHIFT)); @@ -305,7 +302,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, /* handle data in 32-bit chunks */ while (num_bytes > 0) { int bytes; - int is_read = 0; int tm, i; tmpdout = 0; @@ -319,6 +315,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, num_bytes -= bytes; + /* clear ready bit */ + setbits_le32(®s->xfer_status, SPI_XFER_STS_RDY); + clrsetbits_le32(®s->command1, SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT, (bytes * 8 - 1) << SPI_CMD1_BIT_LEN_SHIFT); @@ -329,20 +328,14 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, * Wait for SPI transmit FIFO to empty, or to time out. * The RX FIFO status will be read and cleared last */ - for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { + for (tm = 0; tm < SPI_TIMEOUT; ++tm) { u32 fifo_status, xfer_status; - fifo_status = readl(®s->fifo_status); - - /* We can exit when we've had both RX and TX activity */ - if (is_read && - (fifo_status & SPI_FIFO_STS_TX_FIFO_EMPTY)) - break; - xfer_status = readl(®s->xfer_status); if (!(xfer_status & SPI_XFER_STS_RDY)) continue; + fifo_status = readl(®s->fifo_status); if (fifo_status & SPI_FIFO_STS_ERR) { debug("%s: got a fifo error: ", __func__); if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF) @@ -367,7 +360,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) { tmpdin = readl(®s->rx_fifo); - is_read = 1; /* swap bytes read in */ if (din != NULL) { @@ -377,6 +369,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, } din += bytes; } + + /* We can exit when we've had both RX and TX */ + break; } } diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 2f2353f..150570e 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o obj-$(CONFIG_TPM_TIS_I2C) += tpm.o obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o +obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c new file mode 100644 index 0000000..ed4b039 --- /dev/null +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/state.h> +#include <asm/unaligned.h> +#include <linux/crc8.h> + +/* TPM NVRAM location indices. */ +#define FIRMWARE_NV_INDEX 0x1007 +#define KERNEL_NV_INDEX 0x1008 + +#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60 + +/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */ +#define ROLLBACK_SPACE_KERNEL_VERSION 2 +#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */ + +struct rollback_space_kernel { + /* Struct version, for backwards compatibility */ + uint8_t struct_version; + /* Unique ID to detect space redefinition */ + uint32_t uid; + /* Kernel versions */ + uint32_t kernel_versions; + /* Reserved for future expansion */ + uint8_t reserved[3]; + /* Checksum (v2 and later only) */ + uint8_t crc8; +} __packed rollback_space_kernel; + +/* + * These numbers derive from adding the sizes of command fields as shown in + * the TPM commands manual. + */ +#define TPM_REQUEST_HEADER_LENGTH 10 +#define TPM_RESPONSE_HEADER_LENGTH 10 + +/* These are the different non-volatile spaces that we emulate */ +enum { + NV_GLOBAL_LOCK, + NV_SEQ_FIRMWARE, + NV_SEQ_KERNEL, + NV_SEQ_COUNT, +}; + +/* Size of each non-volatile space */ +#define NV_DATA_SIZE 0x20 + +/* + * Information about our TPM emulation. This is preserved in the sandbox + * state file if enabled. + */ +static struct tpm_state { + uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE]; +} state; + +/** + * sandbox_tpm_read_state() - read the sandbox EC state from the state file + * + * If data is available, then blob and node will provide access to it. If + * not this function sets up an empty TPM. + * + * @blob: Pointer to device tree blob, or NULL if no data to read + * @node: Node offset to read from + */ +static int sandbox_tpm_read_state(const void *blob, int node) +{ + const char *prop; + int len; + int i; + + if (!blob) + return 0; + + for (i = 0; i < NV_SEQ_COUNT; i++) { + char prop_name[20]; + + sprintf(prop_name, "nvdata%d", i); + prop = fdt_getprop(blob, node, prop_name, &len); + if (prop && len == NV_DATA_SIZE) + memcpy(state.nvdata[i], prop, NV_DATA_SIZE); + } + + return 0; +} + +/** + * cros_ec_write_state() - Write out our state to the state file + * + * The caller will ensure that there is a node ready for the state. The node + * may already contain the old state, in which case it is overridden. + * + * @blob: Device tree blob holding state + * @node: Node to write our state into + */ +static int sandbox_tpm_write_state(void *blob, int node) +{ + int i; + + /* + * We are guaranteed enough space to write basic properties. + * We could use fdt_add_subnode() to put each set of data in its + * own node - perhaps useful if we add access informaiton to each. + */ + for (i = 0; i < NV_SEQ_COUNT; i++) { + char prop_name[20]; + + sprintf(prop_name, "nvdata%d", i); + fdt_setprop(blob, node, prop_name, state.nvdata[i], + NV_DATA_SIZE); + } + + return 0; +} + +SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state, + sandbox_tpm_write_state); + +static int index_to_seq(uint32_t index) +{ + switch (index) { + case FIRMWARE_NV_INDEX: + return NV_SEQ_FIRMWARE; + case KERNEL_NV_INDEX: + return NV_SEQ_KERNEL; + case 0: + return NV_GLOBAL_LOCK; + } + + printf("Invalid nv index %#x\n", index); + return -1; +} + +int tis_sendrecv(const u8 *sendbuf, size_t send_size, + u8 *recvbuf, size_t *recv_len) +{ + struct tpm_state *tpm = &state; + uint32_t code, index, length, type; + uint8_t *data; + int seq; + + code = get_unaligned_be32(sendbuf + sizeof(uint16_t) + + sizeof(uint32_t)); + printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size, + *recv_len, code); + print_buffer(0, sendbuf, 1, send_size, 0); + switch (code) { + case 0x65: /* get flags */ + type = get_unaligned_be32(sendbuf + 14); + switch (type) { + case 4: + index = get_unaligned_be32(sendbuf + 18); + printf("Get flags index %#02x\n", index); + *recv_len = 22; + memset(recvbuf, '\0', *recv_len); + put_unaligned_be32(22, recvbuf + + TPM_RESPONSE_HEADER_LENGTH); + data = recvbuf + TPM_RESPONSE_HEADER_LENGTH + + sizeof(uint32_t); + switch (index) { + case FIRMWARE_NV_INDEX: + break; + case KERNEL_NV_INDEX: + /* TPM_NV_PER_PPWRITE */ + put_unaligned_be32(1, data + + NV_DATA_PUBLIC_PERMISSIONS_OFFSET); + break; + } + break; + case 0x11: /* TPM_CAP_NV_INDEX */ + index = get_unaligned_be32(sendbuf + 18); + printf("Get cap nv index %#02x\n", index); + put_unaligned_be32(22, recvbuf + + TPM_RESPONSE_HEADER_LENGTH); + break; + default: + printf(" ** Unknown 0x65 command type %#02x\n", + type); + return -1; + } + break; + case 0xcd: /* nvwrite */ + index = get_unaligned_be32(sendbuf + 10); + length = get_unaligned_be32(sendbuf + 18); + seq = index_to_seq(index); + if (seq < 0) + return -1; + printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length); + memcpy(&tpm->nvdata[seq], sendbuf + 22, length); + *recv_len = 12; + memset(recvbuf, '\0', *recv_len); + break; + case 0xcf: /* nvread */ + index = get_unaligned_be32(sendbuf + 10); + length = get_unaligned_be32(sendbuf + 18); + seq = index_to_seq(index); + if (seq < 0) + return -1; + printf("tpm: nvread index=%#02x, len=%#02x\n", index, length); + *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) + + length; + memset(recvbuf, '\0', *recv_len); + put_unaligned_be32(length, recvbuf + + TPM_RESPONSE_HEADER_LENGTH); + if (seq == NV_SEQ_KERNEL) { + struct rollback_space_kernel rsk; + + data = recvbuf + TPM_RESPONSE_HEADER_LENGTH + + sizeof(uint32_t); + rsk.struct_version = 2; + rsk.uid = ROLLBACK_SPACE_KERNEL_UID; + rsk.kernel_versions = 0; + rsk.crc8 = crc8((unsigned char *)&rsk, + offsetof(struct rollback_space_kernel, + crc8)); + memcpy(data, &rsk, sizeof(rsk)); + } else { + memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH + + sizeof(uint32_t), &tpm->nvdata[seq], length); + } + break; + case 0x14: /* tpm extend */ + case 0x15: /* pcr read */ + case 0x5d: /* force clear */ + case 0x6f: /* physical enable */ + case 0x72: /* physical set deactivated */ + case 0x99: /* startup */ + case 0x4000000a: /* assert physical presence */ + *recv_len = 12; + memset(recvbuf, '\0', *recv_len); + break; + default: + printf("Unknown tpm command %02x\n", code); + return -1; + } + + return 0; +} + +int tis_open(void) +{ + printf("%s\n", __func__); + return 0; +} + +int tis_close(void) +{ + printf("%s\n", __func__); + return 0; +} + +int tis_init(void) +{ + printf("%s\n", __func__); + return 0; +} diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index f52d3f4..f13b172 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -5,12 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ # -# if defined(CONFIG_USB_GADGET) || defined(CONFIG_USB_ETHER) -# Everytime you forget how crufty makefiles can get things like -# this remind you... -ifneq (,$(CONFIG_USB_GADGET)$(CONFIG_USB_ETHER)) -obj-y += epautoconf.o config.o usbstring.o -endif +obj-$(CONFIG_USB_GADGET) += epautoconf.o config.o usbstring.o +obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o # new USB gadget layer dependencies ifdef CONFIG_USB_GADGET diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 37d04a1..a045864 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -40,6 +40,7 @@ struct f_dfu { /* Send/received block number is handy for data integrity check */ int blk_seq_num; + unsigned int poll_timeout; }; typedef int (*dfu_state_fn) (struct f_dfu *, @@ -128,6 +129,33 @@ static struct usb_gadget_strings *dfu_strings[] = { NULL, }; +static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms) +{ + /* + * The bwPollTimeout DFU_GETSTATUS request payload provides information + * about minimum time, in milliseconds, that the host should wait before + * sending a subsequent DFU_GETSTATUS request + * + * This permits the device to vary the delay depending on its need to + * erase or program the memory + * + */ + + unsigned char *p = (unsigned char *)&ms; + + if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) { + dstat->bwPollTimeout[0] = 0; + dstat->bwPollTimeout[1] = 0; + dstat->bwPollTimeout[2] = 0; + + return; + } + + dstat->bwPollTimeout[0] = *p++; + dstat->bwPollTimeout[1] = *p++; + dstat->bwPollTimeout[2] = *p; +} + /*-------------------------------------------------------------------------*/ static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req) @@ -157,11 +185,15 @@ static void handle_getstatus(struct usb_request *req) break; } + dfu_set_poll_timeout(dstat, 0); + + if (f_dfu->poll_timeout) + if (!(f_dfu->blk_seq_num % + (dfu_get_buf_size() / DFU_USB_BUFSIZ))) + dfu_set_poll_timeout(dstat, f_dfu->poll_timeout); + /* send status response */ dstat->bStatus = f_dfu->dfu_status; - dstat->bwPollTimeout[0] = 0; - dstat->bwPollTimeout[1] = 0; - dstat->bwPollTimeout[2] = 0; dstat->bState = f_dfu->dfu_state; dstat->iString = 0; } @@ -723,8 +755,9 @@ static int dfu_bind_config(struct usb_configuration *c) f_dfu->usb_function.unbind = dfu_unbind; f_dfu->usb_function.set_alt = dfu_set_alt; f_dfu->usb_function.disable = dfu_disable; - f_dfu->usb_function.strings = dfu_generic_strings, - f_dfu->usb_function.setup = dfu_handle, + f_dfu->usb_function.strings = dfu_generic_strings; + f_dfu->usb_function.setup = dfu_handle; + f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT; status = usb_add_function(c, &f_dfu->usb_function); if (status) diff --git a/drivers/usb/gadget/f_dfu.h b/drivers/usb/gadget/f_dfu.h index cc2c455..0c29954 100644 --- a/drivers/usb/gadget/f_dfu.h +++ b/drivers/usb/gadget/f_dfu.h @@ -82,4 +82,6 @@ struct dfu_function_descriptor { __le16 wTransferSize; __le16 bcdDFUVersion; } __packed; + +#define DFU_POLL_TIMEOUT_MASK (0xFFFFFFUL) #endif /* __F_DFU_H_ */ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8bd1eb8..17187ca 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -201,6 +201,9 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl) int i, ret = 0; uint32_t cmd, reg; + if (!ctrl || !ctrl->hcor) + return -EINVAL; + cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd &= ~(CMD_PSE | CMD_ASE); ehci_writel(&ctrl->hcor->or_usbcmd, cmd); @@ -945,7 +948,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) #endif /* Set the high address word (aka segment) for 64-bit controller */ if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1) - ehci_writel(ehcic[index].hcor->or_ctrldssegment, 0); + ehci_writel(&ehcic[index].hcor->or_ctrldssegment, 0); qh_list = &ehcic[index].qh_list; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 7a1ffe5..991b199 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -54,9 +54,31 @@ static pci_dev_t ehci_find_class(int index) bdf += PCI_BDF(0, 0, 1)) { pci_read_config_dword(bdf, PCI_CLASS_REVISION, &class); - if ((class >> 8 == PCI_CLASS_SERIAL_USB_EHCI) - && !index--) - return bdf; + class >>= 8; + /* + * Here be dragons! In case we have multiple + * PCI EHCI controllers, this function will + * be called multiple times as well. This + * function will scan the PCI busses, always + * starting from bus 0, device 0, function 0, + * until it finds an USB controller. The USB + * stack gives us an 'index' of a controller + * that is currently being registered, which + * is a number, starting from 0 and growing + * in ascending order as controllers are added. + * To avoid probing the same controller in tne + * subsequent runs of this function, we will + * skip 'index - 1' detected controllers and + * report the index'th controller. + */ + if (class != PCI_CLASS_SERIAL_USB_EHCI) + continue; + if (index) { + index--; + continue; + } + /* Return index'th controller. */ + return bdf; } } } diff --git a/drivers/video/ipu_disp.c b/drivers/video/ipu_disp.c index 22ac142..cefd2dc 100644 --- a/drivers/video/ipu_disp.c +++ b/drivers/video/ipu_disp.c @@ -889,7 +889,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, debug("panel size = %d x %d\n", width, height); if ((v_sync_width == 0) || (h_sync_width == 0)) - return EINVAL; + return -EINVAL; adapt_panel_to_ipu_restricitions(&pixel_clk, width, height, h_start_width, h_end_width, |