diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2012-07-02 11:08:03 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2012-07-02 11:08:03 +0200 |
commit | d04ce5dfe7d2a7502c9a77952164dd6a1e1666a4 (patch) | |
tree | e3cc1f97ef08950b42223b7334dffe8a721c9a6e /arch/arm/mach-mxs | |
parent | 1510c57e93fdfdc8f5f6f6b2bbce44ac9a313172 (diff) | |
parent | 0256d59a41d2ee933fa6e5cc6ee3e933749171e9 (diff) | |
download | barebox-d04ce5dfe7d2a7502c9a77952164dd6a1e1666a4.tar.gz barebox-d04ce5dfe7d2a7502c9a77952164dd6a1e1666a4.tar.xz |
Merge branch 'for-next/mxs-nand'
Conflicts:
arch/arm/mach-mxs/Kconfig
arch/arm/mach-mxs/Makefile
drivers/Makefile
Diffstat (limited to 'arch/arm/mach-mxs')
-rw-r--r-- | arch/arm/mach-mxs/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mach-mxs/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-mxs/bcb.c | 399 | ||||
-rw-r--r-- | arch/arm/mach-mxs/common.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/clock-imx23.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/clock-imx28.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/dma.h | 145 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/imx23-regs.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/imx28-regs.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-mxs/include/mach/mxs.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-mxs/speed-imx23.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-mxs/speed-imx28.c | 19 |
12 files changed, 639 insertions, 2 deletions
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig index 9ce7c7a1bd..746c986083 100644 --- a/arch/arm/mach-mxs/Kconfig +++ b/arch/arm/mach-mxs/Kconfig @@ -92,6 +92,14 @@ config MXS_OCOTP_WRITABLE enable writing: ocotp0.permanent_write_enable=1 +config MXS_CMD_BCB + depends on NAND_MXS + tristate "Nand bcb command" + help + To be able to boot from NAND the i.MX23/28 need a Boot Control Block + in flash. This option enabled the 'bcb' command which can be used to + generate this block during runtime. + endmenu menu "Board specific settings " diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile index 9a42a5f176..fe93096dad 100644 --- a/arch/arm/mach-mxs/Makefile +++ b/arch/arm/mach-mxs/Makefile @@ -1,5 +1,6 @@ -obj-y += imx.o iomux-imx.o power.o +obj-y += imx.o iomux-imx.o power.o common.o obj-$(CONFIG_DRIVER_VIDEO_STM) += imx_lcd_clk.o obj-$(CONFIG_ARCH_IMX23) += speed-imx23.o clocksource-imx23.o usb-imx23.o soc-imx23.o obj-$(CONFIG_ARCH_IMX28) += speed-imx28.o clocksource-imx28.o usb-imx28.o soc-imx28.o obj-$(CONFIG_MXS_OCOTP) += ocotp.o +obj-$(CONFIG_MXS_CMD_BCB) += bcb.o diff --git a/arch/arm/mach-mxs/bcb.c b/arch/arm/mach-mxs/bcb.c new file mode 100644 index 0000000000..d0a3ddc8d3 --- /dev/null +++ b/arch/arm/mach-mxs/bcb.c @@ -0,0 +1,399 @@ +/* + * (C) Copyright 2011 Wolfram Sang, Pengutronix e.K. + * + * 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. + * + * Based on a similar function in Karo Electronics TX28-U-Boot (flash.c). + * Probably written by Lothar Waßmann (like tx28.c). + */ + +#include <common.h> +#include <command.h> +#include <environment.h> +#include <malloc.h> +#include <nand.h> +#include <sizes.h> +#include <errno.h> +#include <io.h> + +#include <mach/imx-regs.h> + +#include <linux/err.h> +#include <linux/mtd/nand.h> + +#define FCB_START_BLOCK 0 +#define NUM_FCB_BLOCKS 1 +#define MAX_FCB_BLOCKS 32768 + +#define GPMI_TIMING0 0x00000070 +#define GPMI_TIMING0_ADDRESS_SETUP_MASK (0xff << 16) +#define GPMI_TIMING0_ADDRESS_SETUP_OFFSET 16 +#define GPMI_TIMING0_DATA_HOLD_MASK (0xff << 8) +#define GPMI_TIMING0_DATA_HOLD_OFFSET 8 +#define GPMI_TIMING0_DATA_SETUP_MASK 0xff +#define GPMI_TIMING0_DATA_SETUP_OFFSET 0 + +#define GPMI_TIMING1 0x00000080 + +#define BCH_MODE 0x00000020 + +#define BCH_FLASH0LAYOUT0 0x00000080 +#define BCH_FLASHLAYOUT0_NBLOCKS_MASK (0xff << 24) +#define BCH_FLASHLAYOUT0_NBLOCKS_OFFSET 24 +#define BCH_FLASHLAYOUT0_META_SIZE_MASK (0xff << 16) +#define BCH_FLASHLAYOUT0_META_SIZE_OFFSET 16 +#define BCH_FLASHLAYOUT0_ECC0_MASK (0xf << 12) +#define BCH_FLASHLAYOUT0_ECC0_OFFSET 12 +#define BCH_FLASHLAYOUT0_DATA0_SIZE_MASK 0xfff +#define BCH_FLASHLAYOUT0_DATA0_SIZE_OFFSET 0 + +#define BCH_FLASH0LAYOUT1 0x00000090 +#define BCH_FLASHLAYOUT1_PAGE_SIZE_MASK (0xffff << 16) +#define BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET 16 +#define BCH_FLASHLAYOUT1_ECCN_MASK (0xf << 12) +#define BCH_FLASHLAYOUT1_ECCN_OFFSET 12 +#define BCH_FLASHLAYOUT1_DATAN_SIZE_MASK 0xfff +#define BCH_FLASHLAYOUT1_DATAN_SIZE_OFFSET 0 + +struct mx28_nand_timing { + u8 data_setup; + u8 data_hold; + u8 address_setup; + u8 dsample_time; + u8 nand_timing_state; + u8 tREA; + u8 tRLOH; + u8 tRHOH; +}; + +struct mx28_fcb { + u32 checksum; + u32 fingerprint; + u32 version; + struct mx28_nand_timing timing; + u32 page_data_size; + u32 total_page_size; + u32 sectors_per_block; + u32 number_of_nands; /* not used by ROM code */ + u32 total_internal_die; /* not used by ROM code */ + u32 cell_type; /* not used by ROM code */ + u32 ecc_blockn_type; + u32 ecc_block0_size; + u32 ecc_blockn_size; + u32 ecc_block0_type; + u32 metadata_size; + u32 ecc_blocks_per_page; + u32 rsrvd[6]; /* not used by ROM code */ + u32 bch_mode; + u32 boot_patch; + u32 patch_sectors; + u32 fw1_start_page; + u32 fw2_start_page; + u32 fw1_sectors; + u32 fw2_sectors; + u32 dbbt_search_area; + u32 bb_mark_byte; + u32 bb_mark_startbit; + u32 bb_mark_phys_offset; +}; + +struct mx28_dbbt_header { + u32 checksum; + u32 fingerprint; + u32 version; + u32 number_bb; + u32 number_pages; + u8 spare[492]; +}; + +struct mx28_dbbt { + u32 nand_number; + u32 number_bb; + u32 bb_num[2040 / 4]; +}; + +#define BF_VAL(v, bf) (((v) & bf##_MASK) >> bf##_OFFSET) +#define GETBIT(v,n) (((v) >> (n)) & 0x1) + +static u8 calculate_parity_13_8(u8 d) +{ + u8 p = 0; + + p |= (GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 3) ^ GETBIT(d, 2)) << 0; + p |= (GETBIT(d, 7) ^ GETBIT(d, 5) ^ GETBIT(d, 4) ^ GETBIT(d, 2) ^ GETBIT(d, 1)) << 1; + p |= (GETBIT(d, 7) ^ GETBIT(d, 6) ^ GETBIT(d, 5) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 2; + p |= (GETBIT(d, 7) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 0)) << 3; + p |= (GETBIT(d, 6) ^ GETBIT(d, 4) ^ GETBIT(d, 3) ^ GETBIT(d, 2) ^ GETBIT(d, 1) ^ GETBIT(d, 0)) << 4; + return p; +} + +static void encode_hamming_13_8(void *_src, void *_ecc, size_t size) +{ + int i; + u8 *src = _src; + u8 *ecc = _ecc; + + for (i = 0; i < size; i++) + ecc[i] = calculate_parity_13_8(src[i]); +} + +static u32 calc_chksum(void *buf, size_t size) +{ + u32 chksum = 0; + u8 *bp = buf; + size_t i; + + for (i = 0; i < size; i++) + chksum += bp[i]; + + return ~chksum; +} + +/* + Physical organisation of data in NAND flash: + metadata + payload chunk 0 (may be empty) + ecc for metadata + payload chunk 0 + payload chunk 1 + ecc for payload chunk 1 +... + payload chunk n + ecc for payload chunk n + */ + +static int calc_bb_offset(struct mtd_info *mtd, struct mx28_fcb *fcb) +{ + int bb_mark_offset; + int chunk_data_size = fcb->ecc_blockn_size * 8; + int chunk_ecc_size = (fcb->ecc_blockn_type << 1) * 13; + int chunk_total_size = chunk_data_size + chunk_ecc_size; + int bb_mark_chunk, bb_mark_chunk_offs; + + bb_mark_offset = (mtd->writesize - fcb->metadata_size) * 8; + if (fcb->ecc_block0_size == 0) + bb_mark_offset -= (fcb->ecc_block0_type << 1) * 13; + + bb_mark_chunk = bb_mark_offset / chunk_total_size; + bb_mark_chunk_offs = bb_mark_offset - (bb_mark_chunk * chunk_total_size); + if (bb_mark_chunk_offs > chunk_data_size) { + printf("Unsupported ECC layout; BB mark resides in ECC data: %u\n", + bb_mark_chunk_offs); + return -EINVAL; + } + bb_mark_offset -= bb_mark_chunk * chunk_ecc_size; + return bb_mark_offset; +} + +static struct mx28_fcb *create_fcb(struct mtd_info *mtd, void *buf, unsigned fw1_start_block, + size_t fw_size, unsigned fw2_start_block) +{ + u32 fl0, fl1, t0; + int metadata_size; + int bb_mark_bit_offs; + struct mx28_fcb *fcb; + int fcb_offs; + void __iomem *bch_regs = (void *)MXS_BCH_BASE; + void __iomem *gpmi_regs = (void *)MXS_GPMI_BASE; + + fl0 = readl(bch_regs + BCH_FLASH0LAYOUT0); + fl1 = readl(bch_regs + BCH_FLASH0LAYOUT1); + t0 = readl(gpmi_regs + GPMI_TIMING0); + metadata_size = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE); + + fcb = buf + ALIGN(metadata_size, 4); + fcb_offs = (void *)fcb - buf; + + memset(buf, 0x00, fcb_offs); + memset(fcb, 0x00, sizeof(*fcb)); + memset(fcb + 1, 0xff, mtd->erasesize - fcb_offs - sizeof(*fcb)); + + strncpy((char *)&fcb->fingerprint, "FCB ", 4); + fcb->version = cpu_to_be32(1); + + fcb->timing.data_setup = BF_VAL(t0, GPMI_TIMING0_DATA_SETUP); + fcb->timing.data_hold = BF_VAL(t0, GPMI_TIMING0_DATA_HOLD); + fcb->timing.address_setup = BF_VAL(t0, GPMI_TIMING0_ADDRESS_SETUP); + + fcb->page_data_size = mtd->writesize; + fcb->total_page_size = mtd->writesize + mtd->oobsize; + fcb->sectors_per_block = mtd->erasesize / mtd->writesize; + + fcb->ecc_block0_type = BF_VAL(fl0, BCH_FLASHLAYOUT0_ECC0); + fcb->ecc_block0_size = BF_VAL(fl0, BCH_FLASHLAYOUT0_DATA0_SIZE); + fcb->ecc_blockn_type = BF_VAL(fl1, BCH_FLASHLAYOUT1_ECCN); + fcb->ecc_blockn_size = BF_VAL(fl1, BCH_FLASHLAYOUT1_DATAN_SIZE); + + fcb->metadata_size = BF_VAL(fl0, BCH_FLASHLAYOUT0_META_SIZE); + fcb->ecc_blocks_per_page = BF_VAL(fl0, BCH_FLASHLAYOUT0_NBLOCKS); + fcb->bch_mode = readl(bch_regs + BCH_MODE); +/* + fcb->boot_patch = 0; + fcb->patch_sectors = 0; +*/ + fcb->fw1_start_page = fw1_start_block / mtd->writesize; + fcb->fw1_sectors = DIV_ROUND_UP(fw_size, mtd->writesize); + + if (fw2_start_block != 0 && fw2_start_block < mtd->size / mtd->erasesize) { + fcb->fw2_start_page = fw2_start_block / mtd->writesize; + fcb->fw2_sectors = fcb->fw1_sectors; + } + + fcb->dbbt_search_area = 1; + + bb_mark_bit_offs = calc_bb_offset(mtd, fcb); + if (bb_mark_bit_offs < 0) + return ERR_PTR(bb_mark_bit_offs); + fcb->bb_mark_byte = bb_mark_bit_offs / 8; + fcb->bb_mark_startbit = bb_mark_bit_offs % 8; + fcb->bb_mark_phys_offset = mtd->writesize; + + fcb->checksum = calc_chksum(&fcb->fingerprint, 512 - 4); + return fcb; +} + +static int find_fcb(struct mtd_info *mtd, void *ref, int page) +{ + int ret = 0; + struct nand_chip *chip = mtd->priv; + void *buf = malloc(mtd->erasesize); + + if (buf == NULL) + return -ENOMEM; + + chip->select_chip(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + ret = chip->ecc.read_page_raw(mtd, chip, buf); + if (ret) { + printf("Failed to read FCB from page %u: %d\n", page, ret); + return ret; + } + chip->select_chip(mtd, -1); + if (memcmp(buf, ref, mtd->writesize) == 0) { + printf("%s: Found FCB in page %u (%08x)\n", __func__, + page, page * mtd->writesize); + ret = 1; + } + free(buf); + return ret; +} + +static int write_fcb(struct mtd_info *mtd, void *buf, int block) +{ + int ret; + struct nand_chip *chip = mtd->priv; + int page = block / mtd->writesize; + struct erase_info erase_opts = { + .mtd = mtd, + .addr = block, + .len = mtd->erasesize, + .callback = NULL, + }; + + ret = find_fcb(mtd, buf, page); + if (ret > 0) { + printf("FCB at block %08x is up to date\n", block); + return 0; + } + + ret = mtd->erase(mtd, &erase_opts); + if (ret) { + printf("Failed to erase FCB block %08x\n", block); + return ret; + } + + printf("Writing FCB to block %08x\n", block); + chip->select_chip(mtd, 0); + ret = chip->write_page(mtd, chip, buf, page, 0, 1); + if (ret) { + printf("Failed to write FCB to block %08x: %d\n", block, ret); + } + chip->select_chip(mtd, -1); + return ret; +} + +int update_bcb(int argc, char *argv[]) +{ + int ret; + int block; + void *buf; + struct mx28_fcb *fcb; + struct cdev *tmp_cdev, *bcb_cdev, *firmware_cdev; + unsigned long fw2_offset = 0; + struct mtd_info *mtd; + unsigned fcb_written = 0; + + if (argc == 1) + return COMMAND_ERROR_USAGE; + + tmp_cdev = cdev_by_name("nand0"); + if (!tmp_cdev || !tmp_cdev->mtd) { + pr_err("%s: No NAND device!\n", __func__); + return -ENODEV; + } + + mtd = tmp_cdev->mtd; + + bcb_cdev = cdev_by_name("nand0.bcb"); + if (!bcb_cdev) { + pr_err("%s: No FCB device!\n", __func__); + return -ENODEV; + } + + firmware_cdev = cdev_by_name(argv[1]); + if (!firmware_cdev) { + pr_err("%s: Bootstream-Image not found!\n", __func__); + return -ENODEV; + } + + if (argc > 2) { + tmp_cdev = cdev_by_name(argv[2]); + if (!tmp_cdev) { + pr_err("%s: Redundant Bootstream-Image not found!\n", __func__); + return -ENODEV; + } + fw2_offset = tmp_cdev->offset; + } + + buf = malloc(mtd->erasesize); + if (!buf) + return -ENOMEM; + + fcb = create_fcb(mtd, buf, firmware_cdev->offset, firmware_cdev->size, fw2_offset); + if (IS_ERR(fcb)) { + printf("Failed to initialize FCB: %ld\n", PTR_ERR(fcb)); + return PTR_ERR(fcb); + } + encode_hamming_13_8(fcb, (void *)fcb + 512, 512); + + for (block = bcb_cdev->offset; block < bcb_cdev->offset + bcb_cdev->size / 2; + block += mtd->erasesize) { + + if (nand_isbad_bbt(mtd, block, false)) + continue; + + ret = write_fcb(mtd, buf, block); + if (ret) { + printf("Failed to write FCB to block %u\n", block); + return ret; + } + + fcb_written++; + } + + return fcb_written ? 0 : -ENOSPC; +} + +BAREBOX_CMD_HELP_START(bcb) +BAREBOX_CMD_HELP_USAGE("bcb <first_bootstream> [second_bootstream]\n") +BAREBOX_CMD_HELP_SHORT("Write a BCB to NAND flash which an MX23/28 needs to boot.\n") +BAREBOX_CMD_HELP_TEXT ("Example: bcb nand0.bootstream\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(bcb) + .cmd = update_bcb, + .usage = "Writes a MX23/28 BCB data structure to flash", + BAREBOX_CMD_HELP(cmd_bcb_help) +BAREBOX_CMD_END diff --git a/arch/arm/mach-mxs/common.c b/arch/arm/mach-mxs/common.c new file mode 100644 index 0000000000..3730633c71 --- /dev/null +++ b/arch/arm/mach-mxs/common.c @@ -0,0 +1,33 @@ +#include <common.h> +#include <io.h> +#include <mach/mxs.h> +#include <mach/imx-regs.h> + +#define MXS_BLOCK_SFTRST (1 << 31) +#define MXS_BLOCK_CLKGATE (1 << 30) + +int mxs_reset_block(void __iomem *reg, int just_enable) +{ + /* Clear SFTRST */ + writel(MXS_BLOCK_SFTRST, reg + BIT_CLR); + mdelay(1); + + /* Clear CLKGATE */ + writel(MXS_BLOCK_CLKGATE, reg + BIT_CLR); + + if (!just_enable) { + /* Set SFTRST */ + writel(MXS_BLOCK_SFTRST, reg + BIT_SET); + mdelay(1); + } + + /* Clear SFTRST */ + writel(MXS_BLOCK_SFTRST, reg + BIT_CLR); + mdelay(1); + + /* Clear CLKGATE */ + writel(MXS_BLOCK_CLKGATE, reg + BIT_CLR); + mdelay(1); + + return 0; +} diff --git a/arch/arm/mach-mxs/include/mach/clock-imx23.h b/arch/arm/mach-mxs/include/mach/clock-imx23.h index 4f20e09d3d..650779278d 100644 --- a/arch/arm/mach-mxs/include/mach/clock-imx23.h +++ b/arch/arm/mach-mxs/include/mach/clock-imx23.h @@ -25,5 +25,6 @@ unsigned imx_set_sspclk(unsigned, unsigned, int); unsigned imx_set_ioclk(unsigned); unsigned imx_set_lcdifclk(unsigned); unsigned imx_get_lcdifclk(void); +void imx_enable_nandclk(void); #endif /* MACH_CLOCK_IMX23_H */ diff --git a/arch/arm/mach-mxs/include/mach/clock-imx28.h b/arch/arm/mach-mxs/include/mach/clock-imx28.h index 613c97b916..0604f0a557 100644 --- a/arch/arm/mach-mxs/include/mach/clock-imx28.h +++ b/arch/arm/mach-mxs/include/mach/clock-imx28.h @@ -27,6 +27,7 @@ unsigned imx_set_lcdifclk(unsigned); unsigned imx_get_lcdifclk(void); unsigned imx_get_fecclk(void); void imx_enable_enetclk(void); +void imx_enable_nandclk(void); #endif /* MACH_CLOCK_IMX28_H */ diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/arch/arm/mach-mxs/include/mach/dma.h new file mode 100644 index 0000000000..52747e2fbf --- /dev/null +++ b/arch/arm/mach-mxs/include/mach/dma.h @@ -0,0 +1,145 @@ +/* + * Freescale i.MX28 APBH DMA + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __DMA_H__ +#define __DMA_H__ + +#include <linux/list.h> + +#ifndef CONFIG_ARCH_DMA_PIO_WORDS +#define DMA_PIO_WORDS 15 +#else +#define DMA_PIO_WORDS CONFIG_ARCH_DMA_PIO_WORDS +#endif + +#define MXS_DMA_ALIGNMENT 32 + +/* + * MXS DMA channels + */ +enum { + MXS_DMA_CHANNEL_AHB_APBH_SSP0 = 0, + MXS_DMA_CHANNEL_AHB_APBH_SSP1, + MXS_DMA_CHANNEL_AHB_APBH_SSP2, + MXS_DMA_CHANNEL_AHB_APBH_SSP3, + MXS_DMA_CHANNEL_AHB_APBH_GPMI0, + MXS_DMA_CHANNEL_AHB_APBH_GPMI1, + MXS_DMA_CHANNEL_AHB_APBH_GPMI2, + MXS_DMA_CHANNEL_AHB_APBH_GPMI3, + MXS_DMA_CHANNEL_AHB_APBH_GPMI4, + MXS_DMA_CHANNEL_AHB_APBH_GPMI5, + MXS_DMA_CHANNEL_AHB_APBH_GPMI6, + MXS_DMA_CHANNEL_AHB_APBH_GPMI7, + MXS_DMA_CHANNEL_AHB_APBH_SSP, + MXS_MAX_DMA_CHANNELS, +}; + +/* + * MXS DMA hardware command. + * + * This structure describes the in-memory layout of an entire DMA command, + * including space for the maximum number of PIO accesses. See the appropriate + * reference manual for a detailed description of what these fields mean to the + * DMA hardware. + */ +#define MXS_DMA_DESC_COMMAND_MASK 0x3 +#define MXS_DMA_DESC_COMMAND_OFFSET 0 +#define MXS_DMA_DESC_COMMAND_NO_DMAXFER 0x0 +#define MXS_DMA_DESC_COMMAND_DMA_WRITE 0x1 +#define MXS_DMA_DESC_COMMAND_DMA_READ 0x2 +#define MXS_DMA_DESC_COMMAND_DMA_SENSE 0x3 +#define MXS_DMA_DESC_CHAIN (1 << 2) +#define MXS_DMA_DESC_IRQ (1 << 3) +#define MXS_DMA_DESC_NAND_LOCK (1 << 4) +#define MXS_DMA_DESC_NAND_WAIT_4_READY (1 << 5) +#define MXS_DMA_DESC_DEC_SEM (1 << 6) +#define MXS_DMA_DESC_WAIT4END (1 << 7) +#define MXS_DMA_DESC_HALT_ON_TERMINATE (1 << 8) +#define MXS_DMA_DESC_TERMINATE_FLUSH (1 << 9) +#define MXS_DMA_DESC_PIO_WORDS_MASK (0xf << 12) +#define MXS_DMA_DESC_PIO_WORDS_OFFSET 12 +#define MXS_DMA_DESC_BYTES_MASK (0xffff << 16) +#define MXS_DMA_DESC_BYTES_OFFSET 16 + +struct mxs_dma_cmd { + unsigned long next; + unsigned long data; + union { + dma_addr_t address; + unsigned long alternate; + }; + unsigned long pio_words[DMA_PIO_WORDS]; +}; + +/* + * MXS DMA command descriptor. + * + * This structure incorporates an MXS DMA hardware command structure, along + * with metadata. + */ +#define MXS_DMA_DESC_FIRST (1 << 0) +#define MXS_DMA_DESC_LAST (1 << 1) +#define MXS_DMA_DESC_READY (1 << 31) + +struct mxs_dma_desc { + struct mxs_dma_cmd cmd; + unsigned int flags; + dma_addr_t address; + void *buffer; + struct list_head node; +}; + +/** + * MXS DMA channel + * + * This structure represents a single DMA channel. The MXS platform code + * maintains an array of these structures to represent every DMA channel in the + * system (see mxs_dma_channels). + */ +#define MXS_DMA_FLAGS_IDLE 0 +#define MXS_DMA_FLAGS_BUSY (1 << 0) +#define MXS_DMA_FLAGS_FREE 0 +#define MXS_DMA_FLAGS_ALLOCATED (1 << 16) +#define MXS_DMA_FLAGS_VALID (1 << 31) + +struct mxs_dma_chan { + const char *name; + unsigned long dev; + struct mxs_dma_device *dma; + unsigned int flags; + unsigned int active_num; + unsigned int pending_num; + struct list_head active; + struct list_head done; +}; + +struct mxs_dma_desc *mxs_dma_desc_alloc(void); +void mxs_dma_desc_free(struct mxs_dma_desc *); +int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc); + +int mxs_dma_go(int chan); +int mxs_dma_init(void); + +#endif /* __DMA_H__ */ diff --git a/arch/arm/mach-mxs/include/mach/imx23-regs.h b/arch/arm/mach-mxs/include/mach/imx23-regs.h index 60f5bf9d6f..7ea3057513 100644 --- a/arch/arm/mach-mxs/include/mach/imx23-regs.h +++ b/arch/arm/mach-mxs/include/mach/imx23-regs.h @@ -27,6 +27,9 @@ #endif #define IMX_MEMORY_BASE 0x40000000 +#define MXS_APBH_BASE 0x80004000 +#define MXS_BCH_BASE 0x8000a000 +#define MXS_GPMI_BASE 0x8000c000 #define IMX_UART1_BASE 0x8006c000 #define IMX_UART2_BASE 0x8006e000 #define IMX_DBGUART_BASE 0x80070000 diff --git a/arch/arm/mach-mxs/include/mach/imx28-regs.h b/arch/arm/mach-mxs/include/mach/imx28-regs.h index 900990a381..16bf5f7a60 100644 --- a/arch/arm/mach-mxs/include/mach/imx28-regs.h +++ b/arch/arm/mach-mxs/include/mach/imx28-regs.h @@ -23,7 +23,9 @@ #define IMX_SRAM_BASE 0x00000000 #define IMX_MEMORY_BASE 0x40000000 -#define IMX_NFC_BASE 0x8000C000 +#define MXS_APBH_BASE 0x80004000 +#define MXS_BCH_BASE 0x8000a000 +#define MXS_GPMI_BASE 0x8000c000 #define IMX_SSP0_BASE 0x80010000 #define IMX_SSP1_BASE 0x80012000 #define IMX_SSP2_BASE 0x80014000 diff --git a/arch/arm/mach-mxs/include/mach/mxs.h b/arch/arm/mach-mxs/include/mach/mxs.h new file mode 100644 index 0000000000..182ed8a998 --- /dev/null +++ b/arch/arm/mach-mxs/include/mach/mxs.h @@ -0,0 +1,6 @@ +#ifndef __MACH_MXS_H +#define __MACH_MXS_H + +int mxs_reset_block(void __iomem *reg, int just_enable); + +#endif /* __MACH_MXS_H */ diff --git a/arch/arm/mach-mxs/speed-imx23.c b/arch/arm/mach-mxs/speed-imx23.c index f41b9bc75a..5d0c90dc8c 100644 --- a/arch/arm/mach-mxs/speed-imx23.c +++ b/arch/arm/mach-mxs/speed-imx23.c @@ -47,6 +47,8 @@ # define GET_SSP_DIV(x) ((x) & CLKCTRL_SSP_DIV_MASK) # define SET_SSP_DIV(x) ((x) & CLKCTRL_SSP_DIV_MASK) #define HW_CLKCTRL_GPMI 0x080 +# define CLKCTRL_GPMI_CLKGATE (1 << 31) +# define CLKCTRL_GPMI_DIV_MASK 0x3ff /* note: no set/clear register! */ #define HW_CLKCTRL_SPDIF 0x090 /* note: no set/clear register! */ @@ -288,6 +290,23 @@ unsigned imx_set_sspclk(unsigned index, unsigned nc, int high) return imx_get_sspclk(index); } +void imx_enable_nandclk(void) +{ + uint32_t reg; + + /* Clear bypass bit; refman says clear, but fsl-code does set. Hooray! */ + writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, + IMX_CCM_BASE + HW_CLKCTRL_CLKSEQ + BIT_SET); + + reg = readl(IMX_CCM_BASE + HW_CLKCTRL_GPMI) & ~CLKCTRL_GPMI_CLKGATE; + writel(reg, IMX_CCM_BASE + HW_CLKCTRL_GPMI); + udelay(1000); + /* Initialize DIV to 1 */ + reg &= ~CLKCTRL_GPMI_DIV_MASK; + reg |= 1; + writel(reg, IMX_CCM_BASE + HW_CLKCTRL_GPMI); +} + void imx_dump_clocks(void) { printf("mpll: %10u kHz\n", imx_get_mpllclk() / 1000); diff --git a/arch/arm/mach-mxs/speed-imx28.c b/arch/arm/mach-mxs/speed-imx28.c index 2641fb6fb2..df55f64c24 100644 --- a/arch/arm/mach-mxs/speed-imx28.c +++ b/arch/arm/mach-mxs/speed-imx28.c @@ -48,6 +48,8 @@ # define GET_SSP_DIV(x) ((x) & CLKCTRL_SSP_DIV_MASK) # define SET_SSP_DIV(x) ((x) & CLKCTRL_SSP_DIV_MASK) #define HW_CLKCTRL_GPMI 0x0d0 +# define CLKCTRL_GPMI_CLKGATE (1 << 31) +# define CLKCTRL_GPMI_DIV_MASK 0x3ff /* note: no set/clear register! */ #define HW_CLKCTRL_SPDIF 0x0e0 /* note: no set/clear register! */ @@ -398,6 +400,23 @@ void imx_enable_enetclk(void) IMX_CCM_BASE + HW_CLKCTRL_ENET); } +void imx_enable_nandclk(void) +{ + uint32_t reg; + + /* Clear bypass bit; refman says clear, but fsl-code does set. Hooray! */ + writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, + IMX_CCM_BASE + HW_CLKCTRL_CLKSEQ + BIT_SET); + + reg = readl(IMX_CCM_BASE + HW_CLKCTRL_GPMI) & ~CLKCTRL_GPMI_CLKGATE; + writel(reg, IMX_CCM_BASE + HW_CLKCTRL_GPMI); + udelay(1000); + /* Initialize DIV to 1 */ + reg &= ~CLKCTRL_GPMI_DIV_MASK; + reg |= 1; + writel(reg, IMX_CCM_BASE + HW_CLKCTRL_GPMI); +} + void imx_dump_clocks(void) { printf("mpll: %10u kHz\n", imx_get_mpllclk() / 1000); |