From c39993fcdbbc1b3b59da6eaf12d7c09c2d70123e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 15 Jan 2015 18:32:34 -0800 Subject: i.MX: SPI: Respect SPI_LSB_FIRST flag in mode settings Add code to support SPI transfers that have data shifted out least significant bit first. This is useful in many cases, but specifically it is needed for drivers/firmware/altera_serial.c to work on i.MX platform. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/spi/imx_spi.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c index 3146339949..a1f19eba8b 100644 --- a/drivers/spi/imx_spi.c +++ b/drivers/spi/imx_spi.c @@ -137,6 +137,25 @@ static int imx_spi_setup(struct spi_device *spi) return 0; } +static unsigned int imx_spi_maybe_reverse_bits(struct spi_device *spi, unsigned int word) +{ + unsigned int result = word; + + if (spi->mode & SPI_LSB_FIRST) { + size_t bits_left = spi->bits_per_word - 1; + + for (word >>= 1; word; word >>= 1) { + result <<= 1; + result |= word & 1; + bits_left--; + } + + result <<= bits_left; + } + + return result; +} + static unsigned int cspi_0_0_xchg_single(struct imx_spi *imx, unsigned int data) { void __iomem *base = imx->regs; @@ -382,9 +401,20 @@ static void cspi_2_3_chipselect(struct spi_device *spi, int is_active) gpio_set_value(gpio, gpio_cs); } -static void imx_spi_do_transfer(struct spi_device *spi, struct spi_transfer *t) +static u32 imx_xchg_single(struct spi_device *spi, u32 tx_val) { + u32 rx_val; struct imx_spi *imx = container_of(spi->master, struct imx_spi, master); + + + tx_val = imx_spi_maybe_reverse_bits(spi, tx_val); + rx_val = imx->xchg_single(imx, tx_val); + + return imx_spi_maybe_reverse_bits(spi, rx_val); +} + +static void imx_spi_do_transfer(struct spi_device *spi, struct spi_transfer *t) +{ unsigned i; if (spi->bits_per_word <= 8) { @@ -393,7 +423,8 @@ static void imx_spi_do_transfer(struct spi_device *spi, struct spi_transfer *t) u8 rx_val; for (i = 0; i < t->len; i++) { - rx_val = imx->xchg_single(imx, tx_buf ? tx_buf[i] : 0); + rx_val = imx_xchg_single(spi, tx_buf ? tx_buf[i] : 0); + if (rx_buf) rx_buf[i] = rx_val; } @@ -403,7 +434,8 @@ static void imx_spi_do_transfer(struct spi_device *spi, struct spi_transfer *t) u16 rx_val; for (i = 0; i < t->len >> 1; i++) { - rx_val = imx->xchg_single(imx, tx_buf ? tx_buf[i] : 0); + rx_val = imx_xchg_single(spi, tx_buf ? tx_buf[i] : 0); + if (rx_buf) rx_buf[i] = rx_val; } @@ -413,7 +445,8 @@ static void imx_spi_do_transfer(struct spi_device *spi, struct spi_transfer *t) u32 rx_val; for (i = 0; i < t->len >> 2; i++) { - rx_val = imx->xchg_single(imx, tx_buf ? tx_buf[i] : 0); + rx_val = imx_xchg_single(spi, tx_buf ? tx_buf[i] : 0); + if (rx_buf) rx_buf[i] = rx_val; } -- cgit v1.2.3 From a114e9b00c6c3f73be8f9de4c4722a6320399252 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Wed, 28 Jan 2015 11:11:15 +0100 Subject: ARM: i.MX6: use generic calculation in nand bbu handler The parameters ECC Strength, BadBlockMarkerByte and BadBlockMarkerStartBit in the FCB structure depends on the nand chip's pagesize and oobsize. Instead of hardcoding these values into the imx6 bbu handler calculate these values on the fly. Therefore we export the necessary functions from the nand_mxs driver to use them in the bbu handler. Signed-off-by: Stefan Christ Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/Kconfig | 1 + arch/arm/mach-imx/imx6-bbu-nand.c | 28 ++++++---------------------- drivers/mtd/nand/nand_mxs.c | 7 ++++--- include/linux/mtd/nand_mxs.h | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 25 deletions(-) create mode 100644 include/linux/mtd/nand_mxs.h (limited to 'drivers') diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 9ac36e1453..477207e646 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -119,6 +119,7 @@ config BAREBOX_UPDATE_IMX6_NAND depends on BAREBOX_UPDATE depends on MTD depends on MTD_WRITE + depends on NAND_MXS default y comment "Freescale i.MX System-on-Chip" diff --git a/arch/arm/mach-imx/imx6-bbu-nand.c b/arch/arm/mach-imx/imx6-bbu-nand.c index 2a54979fcb..d2bfedbad5 100644 --- a/arch/arm/mach-imx/imx6-bbu-nand.c +++ b/arch/arm/mach-imx/imx6-bbu-nand.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -235,22 +236,9 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) fcb->TotalPageSize = mtd->writesize + mtd->oobsize; fcb->SectorsPerBlock = mtd->erasesize / mtd->writesize; - if (mtd->writesize == 2048) { - fcb->EccBlock0EccType = 4; - } else if (mtd->writesize == 4096) { - if (mtd->oobsize == 218) { - fcb->EccBlock0EccType = 8; - } else if (mtd->oobsize == 128) { - fcb->EccBlock0EccType = 4; - } else { - pr_err("Illegal oobsize %d\n", mtd->oobsize); - return -EINVAL; - } - } else { - pr_err("Illegal writesize %d\n", mtd->writesize); - return -EINVAL; - } - + /* Divide ECC strength by two and save the value into FCB structure. */ + fcb->EccBlock0EccType = + mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1; fcb->EccBlockNEccType = fcb->EccBlock0EccType; /* Also hardcoded in kobs-ng */ @@ -267,12 +255,8 @@ static int fcb_create(struct fcb_block *fcb, struct mtd_info *mtd) /* DBBT search area starts at third block */ fcb->DBBTSearchAreaStartAddress = mtd->erasesize / mtd->writesize * 2; - if (mtd->writesize == 2048) { - fcb->BadBlockMarkerByte = 0x000007cf; - } else { - pr_err("BadBlockMarkerByte unknown for writesize %d\n", mtd->writesize); - return -EINVAL; - } + fcb->BadBlockMarkerByte = mxs_nand_mark_byte_offset(mtd); + fcb->BadBlockMarkerStartBit = mxs_nand_mark_bit_offset(mtd); fcb->BBMarkerPhysicalOffset = mtd->writesize; diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c index 94101a3d98..4e38e09186 100644 --- a/drivers/mtd/nand/nand_mxs.c +++ b/drivers/mtd/nand/nand_mxs.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -231,7 +232,7 @@ static uint32_t mxs_nand_aux_status_offset(void) return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3; } -static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, +uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, uint32_t page_oob_size) { int ecc_chunk_count = mxs_nand_ecc_chunk_cnt(page_data_size); @@ -294,14 +295,14 @@ static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size, return block_mark_bit_offset; } -static uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd) +uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd) { uint32_t ecc_strength; ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize); return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) >> 3; } -static uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd) +uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd) { uint32_t ecc_strength; ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize); diff --git a/include/linux/mtd/nand_mxs.h b/include/linux/mtd/nand_mxs.h new file mode 100644 index 0000000000..eca31777f5 --- /dev/null +++ b/include/linux/mtd/nand_mxs.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 PHYTEC Messtechnik GmbH, + * Author: Stefan Christ + * + * This program 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __NAND_MXS_H +#define __NAND_MXS_H + +/* + * Functions are definied in drivers/mtd/nand/nand_mxs.c. They are used to + * calculate the ECC Strength, BadBlockMarkerByte and BadBlockMarkerStartBit + * which are placed into the FCB structure. The i.MX6 ROM needs these + * parameters to read the firmware from NAND. + * + * The parameters depends on the pagesize and oobsize of NAND chips and are + * different for each combination. To avoid placing hardcoded values in the bbu + * update handler code, the generic calculation from the driver code is used. + */ + +uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, + uint32_t page_oob_size); + +uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd); + +uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd); + +#endif /* __NAND_MXS_H */ -- cgit v1.2.3