From 6dc75c7438f31ca711cbbe4be5a386e69976407b Mon Sep 17 00:00:00 2001 From: Yonghui Yu Date: Mon, 15 May 2017 11:49:39 +0800 Subject: [PATCH] nand: update config for mtd driver PD#142470: update nand config for mtd 1. update dts of skt&s400 2. update clock reg 3. update regbase 4. update bchmode for infopage 5. mtd: support desctrete uboot layout for slc change uboot layout for slc [3/3] multi bootloaders were stored in mlc/slc/emmc. For emmc/mlc, there's enough space at the begining. bl2&fip can be stored together which we may call it as compact mode. |bl2|fip|bl2|fip|bl2|fip|rsv|normal| But for slc, space is restricted by romboot. bl2 and fip had to be stored discretely. |bl2|bl2|bl2|bl2|rsv|fip|fip|fip|fip|normal| If kernle want mtd driver use descrete mode. 1. bl_mode in dts should be set as 1. 2. fip_copies and fip_size should be the same as uboot which was described by marco CONFIG_TPL_COPY_NUM&CONFIG_TPL_SIZE_PER_COPY. 3. And the tpl partition should be added in mtd partition table whose offset and size are negligible. when using, mtd0 is for bl2, mtd1 is for tpl(fip) Change-Id: I0ed07168ba7497d674a7160f7966ebb484a123d5 Signed-off-by: Yonghui Yu --- MAINTAINERS | 2 + arch/arm64/boot/dts/amlogic/axg_a113d_skt.dts | 86 ++ arch/arm64/boot/dts/amlogic/axg_s400.dts | 88 ++ arch/arm64/boot/dts/amlogic/axg_s420.dts | 88 ++ arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts | 25 + arch/arm64/boot/dts/amlogic/mesonaxg.dtsi | 51 + drivers/amlogic/mtd/Makefile | 3 +- drivers/amlogic/mtd/aml_hwctrl.h | 13 +- drivers/amlogic/mtd/aml_mtd.h | 55 +- drivers/amlogic/mtd/aml_nand.c | 95 +- drivers/amlogic/mtd/boot.c | 1043 +++++++++++++++++ drivers/amlogic/mtd/m3_nand.c | 554 +-------- drivers/amlogic/mtd/mtd_driver.c | 32 + drivers/amlogic/mtd/nand_flash.c | 2 +- drivers/amlogic/pinctrl/pinctrl-mesonaxg.c | 16 +- 15 files changed, 1617 insertions(+), 536 deletions(-) create mode 100644 drivers/amlogic/mtd/boot.c diff --git a/MAINTAINERS b/MAINTAINERS index aacc4c77b10a..b588b9e22f1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13615,6 +13615,8 @@ F: include/linux/mmc/host.h AMLOGIC MTD DRIVER M: Liang Yang F: drivers/amlogic/mtd/ +M: Yonghui Yu +F: drivers/amlogic/mtd/boot.c AMLOGIC GPU DEVICETREE M: Jiyu Yang diff --git a/arch/arm64/boot/dts/amlogic/axg_a113d_skt.dts b/arch/arm64/boot/dts/amlogic/axg_a113d_skt.dts index 9e941b867449..f1c1cfa4edb5 100644 --- a/arch/arm64/boot/dts/amlogic/axg_a113d_skt.dts +++ b/arch/arm64/boot/dts/amlogic/axg_a113d_skt.dts @@ -56,7 +56,93 @@ }; }; + mtd_nand { + compatible = "amlogic, aml_mtd_nand"; + dev_name = "mtdnand"; + status = "okay"; + reg = <0x0 0xFFE07800 0x0 0x200>; + interrupts = < 0 34 1 >; + pinctrl-names = "nand_rb_mod","nand_norb_mod", "nand_cs_only"; + pinctrl-0 = <&all_nand_pins>; + pinctrl-1 = <&all_nand_pins>; + pinctrl-2 = <&nand_cs_pins>; + device_id = <0>; + /*fip/tpl configurations, must be same + * with uboot if bl_mode was set as 1 + * bl_mode: 0 compact mode; 1 descrete mode + * if bl_mode was set as 1, fip configeration will work + */ + bl_mode = <1>; + /*copy count of fip*/ + fip_copies = <4>; + /*size of each fip copy */ + fip_size = <0x200000>; + nand_clk_ctrl = <0xFFE07000>; + plat-names = "bootloader","nandnormal"; + plat-num = <2>; + plat-part-0 = <&bootloader>; + plat-part-1 = <&nandnormal>; + bootloader: bootloader{ + enable_pad ="ce0"; + busy_pad = "rb0"; + timming_mode = "mode5"; + bch_mode = "bch8_1k"; + t_rea = <20>; + t_rhoh = <15>; + chip_num = <1>; + part_num = <0>; + rb_detect = <1>; + }; + nandnormal: nandnormal{ + enable_pad ="ce0"; + busy_pad = "rb0"; + timming_mode = "mode5"; + bch_mode = "bch8_1k"; + plane_mode = "twoplane"; + t_rea = <20>; + t_rhoh = <15>; + chip_num = <2>; + part_num = <3>; + partition = <&nand_partitions>; + rb_detect = <1>; + }; + nand_partitions:nand_partition{ + /* + * if bl_mode is 1, tpl size was generate by + * fip_copies * fip_size which + * will not skip bad when calculating + * the partition size; + * + * if bl_mode is 0, + * tpl partition must be comment out. + */ + tpl{ + offset=<0x0 0x0>; + size=<0x0 0x0>; + }; + logo{ + offset=<0x0 0x0>; + size=<0x0 0x200000>; + }; + recovery{ + offset=<0x0 0x0>; + size=<0x0 0x1000000>; + }; + boot{ + offset=<0x0 0x0>; + size=<0x0 0xC00000>; + }; + system{ + offset=<0x0 0x0>; + size=<0x0 0xDC40000>; + }; + data{ + offset=<0xffffffff 0xffffffff>; + size=<0x0 0x0>; + }; + }; + }; dwc3: dwc3@ff500000 { compatible = "synopsys, dwc3"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400.dts b/arch/arm64/boot/dts/amlogic/axg_s400.dts index 994e3b445d88..580ac9c401d9 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400.dts @@ -55,6 +55,94 @@ no-map; }; }; + mtd_nand { + compatible = "amlogic, aml_mtd_nand"; + dev_name = "mtdnand"; + status = "okay"; + reg = <0x0 0xFFE07800 0x0 0x200>; + interrupts = < 0 34 1 >; + pinctrl-names = "nand_rb_mod","nand_norb_mod", "nand_cs_only"; + pinctrl-0 = <&all_nand_pins>; + pinctrl-1 = <&all_nand_pins>; + pinctrl-2 = <&nand_cs_pins>; + device_id = <0>; + + /*fip/tpl configurations, must be same + * with uboot if bl_mode was set as 1 + * bl_mode: 0 compact mode; 1 descrete mode + * if bl_mode was set as 1, fip configeration will work + */ + bl_mode = <1>; + /*copy count of fip*/ + fip_copies = <4>; + /*size of each fip copy */ + fip_size = <0x200000>; + nand_clk_ctrl = <0xFFE07000>; + plat-names = "bootloader","nandnormal"; + plat-num = <2>; + plat-part-0 = <&bootloader>; + plat-part-1 = <&nandnormal>; + bootloader: bootloader{ + enable_pad ="ce0"; + busy_pad = "rb0"; + timming_mode = "mode5"; + bch_mode = "bch8_1k"; + t_rea = <20>; + t_rhoh = <15>; + chip_num = <1>; + part_num = <0>; + rb_detect = <1>; + }; + nandnormal: nandnormal{ + enable_pad ="ce0"; + busy_pad = "rb0"; + timming_mode = "mode5"; + bch_mode = "bch8_1k"; + plane_mode = "twoplane"; + t_rea = <20>; + t_rhoh = <15>; + chip_num = <2>; + part_num = <3>; + partition = <&nand_partitions>; + rb_detect = <1>; + }; + nand_partitions:nand_partition{ + /* + * if bl_mode is 1, tpl size was generate by + * fip_copies * fip_size which + * will not skip bad when calculating + * the partition size; + * + * if bl_mode is 0, + * tpl partition must be comment out. + */ + tpl{ + offset=<0x0 0x0>; + size=<0x0 0x0>; + }; + logo{ + offset=<0x0 0x0>; + size=<0x0 0x200000>; + }; + recovery{ + offset=<0x0 0x0>; + size=<0x0 0x1000000>; + }; + boot{ + offset=<0x0 0x0>; + size=<0x0 0xC00000>; + }; + system{ + offset=<0x0 0x0>; + size=<0x0 0xDC40000>; + }; + data{ + offset=<0xffffffff 0xffffffff>; + size=<0x0 0x0>; + }; + }; + }; + dwc3: dwc3@ff500000 { compatible = "synopsys, dwc3"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s420.dts b/arch/arm64/boot/dts/amlogic/axg_s420.dts index c44aa543e60b..82911e5a2b23 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420.dts @@ -56,6 +56,94 @@ }; }; + mtd_nand { + compatible = "amlogic, aml_mtd_nand"; + dev_name = "mtdnand"; + status = "okay"; + reg = <0x0 0xFFE07800 0x0 0x200>; + interrupts = < 0 34 1 >; + pinctrl-names = "nand_rb_mod","nand_norb_mod", "nand_cs_only"; + pinctrl-0 = <&all_nand_pins>; + pinctrl-1 = <&all_nand_pins>; + pinctrl-2 = <&nand_cs_pins>; + device_id = <0>; + + /*fip/tpl configurations, must be same + * with uboot if bl_mode was set as 1 + * bl_mode: 0 compact mode; 1 descrete mode + * if bl_mode was set as 1, fip configeration will work + */ + bl_mode = <1>; + /*copy count of fip*/ + fip_copies = <4>; + /*size of each fip copy */ + fip_size = <0x200000>; + nand_clk_ctrl = <0xFFE07000>; + plat-names = "bootloader","nandnormal"; + plat-num = <2>; + plat-part-0 = <&bootloader>; + plat-part-1 = <&nandnormal>; + bootloader: bootloader{ + enable_pad ="ce0"; + busy_pad = "rb0"; + timming_mode = "mode5"; + bch_mode = "bch8_1k"; + t_rea = <20>; + t_rhoh = <15>; + chip_num = <1>; + part_num = <0>; + rb_detect = <1>; + }; + nandnormal: nandnormal{ + enable_pad ="ce0"; + busy_pad = "rb0"; + timming_mode = "mode5"; + bch_mode = "bch8_1k"; + plane_mode = "twoplane"; + t_rea = <20>; + t_rhoh = <15>; + chip_num = <2>; + part_num = <3>; + partition = <&nand_partitions>; + rb_detect = <1>; + }; + nand_partitions:nand_partition{ + /* + * if bl_mode is 1, tpl size was generate by + * fip_copies * fip_size which + * will not skip bad when calculating + * the partition size; + * + * if bl_mode is 0, + * tpl partition must be comment out. + */ + tpl{ + offset=<0x0 0x0>; + size=<0x0 0x0>; + }; + logo{ + offset=<0x0 0x0>; + size=<0x0 0x200000>; + }; + recovery{ + offset=<0x0 0x0>; + size=<0x0 0x1000000>; + }; + boot{ + offset=<0x0 0x0>; + size=<0x0 0xC00000>; + }; + system{ + offset=<0x0 0x0>; + size=<0x0 0xDC40000>; + }; + data{ + offset=<0xffffffff 0xffffffff>; + size=<0x0 0x0>; + }; + }; + }; + dwc3: dwc3@ff500000 { compatible = "synopsys, dwc3"; status = "okay"; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts index 3f7299ae5909..96ccf2aee015 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p401_2g.dts @@ -244,6 +244,18 @@ pinctrl-1 = <&all_nand_pins>; pinctrl-2 = <&nand_cs_pins>; device_id = <0>; + + /*fip/tpl configurations, must be same + * with uboot if bl_mode was set as 1 + * bl_mode: 0 compact mode; 1 descrete mode + * if bl_mode was set as 1, fip configeration will work + */ + bl_mode = <1>; + /*copy count of fip*/ + fip_copies = <4>; + /*size of each fip copy */ + fip_size = <0x200000>; + nand_clk_ctrl = <0xd0074000>; plat-names = "bootloader","nandnormal"; plat-num = <2>; plat-part-0 = <&bootloader>; @@ -273,6 +285,19 @@ rb_detect = <1>; }; nand_partitions:nand_partition{ + /* + * if bl_mode is 1, tpl size was generate by + * fip_copies * fip_size which + * will not skip bad when calculating + * the partition size; + * + * if bl_mode is 0, + * tpl partition must be comment out. + */ + tpl{ + offset=<0x0 0x0>; + size=<0x0 0x0>; + }; logo{ offset=<0x0 0x0>; size=<0x0 0x200000>; diff --git a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi index bbe842cf6628..343eb81abf75 100644 --- a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi @@ -592,6 +592,57 @@ function = "spi_b"; }; }; + nand_pulldown: nand_pulldown { + mux { + pins = "BOOT_0", + "BOOT_1", + "BOOT_2", + "BOOT_3", + "BOOT_4", + "BOOT_5", + "BOOT_6", + "BOOT_7", + "BOOT_13"; + function = "nandflash"; + bias-pull-down; + }; + }; + + nand_pullup: nand_pullup { + mux { + pins = "BOOT_8"; + function = "nandflash"; + bias-pull-up; + }; + }; + + all_nand_pins: all_nand_pins { + mux { + pins = "BOOT_0", + "BOOT_1", + "BOOT_2", + "BOOT_3", + "BOOT_4", + "BOOT_5", + "BOOT_6", + "BOOT_7", + "BOOT_8", + "BOOT_9", + "BOOT_10", + "BOOT_11", + "BOOT_12", + "BOOT_13"; + function = "nandflash"; + input-enable; + }; + }; + + nand_cs_pins: nand_cs { + mux { + pins = "BOOT_8"; + function = "nandflash"; + }; + }; }; /* end of pinctrl_periphs */ diff --git a/drivers/amlogic/mtd/Makefile b/drivers/amlogic/mtd/Makefile index 9cb6f86444c6..cfaafc1f1b88 100644 --- a/drivers/amlogic/mtd/Makefile +++ b/drivers/amlogic/mtd/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_AMLOGIC_NAND) += aml_nand.o \ rsv_manage.o \ nand_flash.o \ mtd_driver.o \ - new_nand.o + new_nand.o \ + boot.o diff --git a/drivers/amlogic/mtd/aml_hwctrl.h b/drivers/amlogic/mtd/aml_hwctrl.h index f362ee1bef2f..7437b651ccf9 100644 --- a/drivers/amlogic/mtd/aml_hwctrl.h +++ b/drivers/amlogic/mtd/aml_hwctrl.h @@ -53,8 +53,8 @@ struct hw_controller { void __iomem *nand_clk_reg; u32 irq; #ifndef AML_NAND_UBOOT - dma_addr_t data_dma_addr; - dma_addr_t info_dma_addr; + /*dma_addr_t data_dma_addr;*/ + /*dma_addr_t info_dma_addr;*/ struct pinctrl *nand_pinctrl; struct pinctrl_state *nand_pinstate; struct pinctrl_state *nand_rbstate; @@ -92,7 +92,9 @@ struct hw_controller { #endif /* 0 */ /* gx, for pxp and ic. */ -#define SD_EMMC_BASE_C (0xd0074000) +//#define SD_EMMC_BASE_C (0xd0074000) +/* axg */ +#define SD_EMMC_BASE_C 0xFFE07000 #define P_NAND_BASE (SD_EMMC_BASE_C | (1<<11)) #define NAND_BASE_APB (P_NAND_BASE) #define NAND_CLK_CNTL (SD_EMMC_BASE_C) @@ -101,9 +103,10 @@ struct hw_controller { #define A0_GP_CFG0 (0xc8100240) #define A0_GP_CFG2 (0xc8100248) -#define NAND_CLK_CNTL (0xd0074000) +#define SD_EMMC_BASE_C 0xFFE07000 +#define NAND_CLK_CNTL (SD_EMMC_BASE_C) #define PINMUX_BASE (0xc8834400 + (0x2c << 2)) -#define P_NAND_BASE (0xd0074000 | (1<<11)) +#define P_NAND_BASE (SD_EMMC_BASE_C | (1<<11)) #define NAND_BASE_APB (P_NAND_BASE) /* NAND Write Command And Read Status Register */ diff --git a/drivers/amlogic/mtd/aml_mtd.h b/drivers/amlogic/mtd/aml_mtd.h index 7d9a33321ae3..6e8c9fa8cd04 100644 --- a/drivers/amlogic/mtd/aml_mtd.h +++ b/drivers/amlogic/mtd/aml_mtd.h @@ -57,6 +57,9 @@ /*#include "partition_table.h"*/ #define CONFIG_MTD_PARTITIONS 1 +#define NAND_MAX_DEVICE 4 +extern struct mtd_info *nand_info[NAND_MAX_DEVICE]; +extern unsigned char pagelist_hynix256[128]; #define CONFIG_ENV_SIZE (64*1024U) /* @@ -117,10 +120,27 @@ struct _ext_info { uint32_t page_per_blk; uint32_t xlc; uint32_t ce_mask; + /* copact mode: boot means whole uboot + * it's easy to understood that copies of + * bl2 and fip are the same. + * discrete mode, boot means the fip only + */ uint32_t boot_num; uint32_t each_boot_pages; - uint32_t rsv[2]; - /* add new below, */ + /* for comptible reason */ + uint32_t bbt_occupy_pages; + uint32_t bbt_start_block; +}; +#define NAND_FIPMODE_COMPACT (0) +#define NAND_FIPMODE_DISCRETE (1) + +struct _fip_info { + /* version */ + uint16_t version; + /* compact or discrete */ + uint16_t mode; + /* fip start, pages */ + uint32_t fip_start; }; /*max size is 384 bytes*/ @@ -129,6 +149,8 @@ struct _nand_page0 { unsigned char page_list[16]; struct _nand_cmd retry_usr[32]; struct _ext_info ext_info; + /* added for slc */ + struct _fip_info fip_info; }; @@ -476,6 +498,8 @@ struct aml_nand_chip { unsigned int rbpin_mode; unsigned int rbpin_detect; unsigned int short_pgsz; + /* bch for infopage on short mode */ + unsigned int bch_info; unsigned int bch_mode; u8 user_byte_mode; @@ -497,6 +521,10 @@ struct aml_nand_chip { /*add property field for key private data*/ int dtbsize; int keysize; + int boot_copy_num; /*tell how many bootloader copies*/ + unsigned int bl_mode; + unsigned int fip_copies; + unsigned int fip_size; u8 key_protect; unsigned char *rsv_data_buf; @@ -553,6 +581,8 @@ struct aml_nand_chip { int (*aml_nand_block_bad_scrub)(struct mtd_info *mtd); }; +struct aml_nand_device; + struct aml_nand_platform { struct aml_nand_flash_dev *nand_flash_dev; char *name; @@ -567,8 +597,9 @@ struct aml_nand_platform { unsigned int rbpin_mode; /*may get from romboot*/ unsigned int rbpin_detect; unsigned int short_pgsz; /*zero means no short*/ - struct aml_nand_chip *aml_chip; + /* back pointer to the device*/ + struct aml_nand_device *aml_nand_device; struct platform_nand_data platform_nand_data; }; @@ -577,6 +608,11 @@ struct aml_nand_device { u8 dev_num; #ifndef AML_NAND_UBOOT struct notifier_block nb; + u32 bl_mode; + u32 fip_copies; + u32 fip_size; + /* for mapping regsters */ + u32 nand_clk_ctrl; #endif }; @@ -803,7 +839,20 @@ void aml_nand_command(struct mtd_info *mtd, int aml_nand_wait(struct mtd_info *mtd, struct nand_chip *chip); int aml_nand_erase_cmd(struct mtd_info *mtd, int page); +/* for boot operations */ +int m3_nand_boot_erase_cmd(struct mtd_info *mtd, int page); +int m3_nand_boot_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, int page); + +int m3_nand_boot_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required, int page); + +int m3_nand_boot_write_page(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offset, int data_len, const uint8_t *buf, + int oob_required, int page, int cached, int raw); + +int boot_device_register(struct aml_nand_chip *aml_chip); int add_mtd_partitions(struct mtd_info *mtd, const struct mtd_partition *part, int num); diff --git a/drivers/amlogic/mtd/aml_nand.c b/drivers/amlogic/mtd/aml_nand.c index 433272a0ecb8..162945bf95e6 100644 --- a/drivers/amlogic/mtd/aml_nand.c +++ b/drivers/amlogic/mtd/aml_nand.c @@ -234,6 +234,50 @@ static struct nand_ecclayout aml_nand_oob_1664 = { .length = 32} } }; #endif +int nand_get_device(struct mtd_info *mtd, int new_state) +{ + struct nand_chip *chip = mtd->priv; + spinlock_t *lock = &chip->controller->lock; + wait_queue_head_t *wq = &chip->controller->wq; + DECLARE_WAITQUEUE(wait, current); +retry: + spin_lock(lock); + + /* Hardware controller shared among independent devices */ + if (!chip->controller->active) + chip->controller->active = chip; + + if (chip->controller->active == chip && chip->state == FL_READY) { + chip->state = new_state; + spin_unlock(lock); + return 0; + } + if (new_state == FL_PM_SUSPENDED) { + if (chip->controller->active->state == FL_PM_SUSPENDED) { + chip->state = FL_PM_SUSPENDED; + spin_unlock(lock); + return 0; + } + } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(wq, &wait); + spin_unlock(lock); + schedule(); + remove_wait_queue(wq, &wait); + goto retry; +} + +void nand_release_device(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + + /* Release the controller and the chip */ + spin_lock(&chip->controller->lock); + chip->controller->active = NULL; + chip->state = FL_READY; + wake_up(&chip->controller->wq); + spin_unlock(&chip->controller->lock); +} void aml_platform_get_user_byte(struct aml_nand_chip *aml_chip, unsigned char *oob_buf, int byte_num) @@ -303,6 +347,8 @@ static int aml_nand_add_partition(struct aml_nand_chip *aml_chip) uint64_t last_size = 0, start_blk = 0; uint64_t mini_part_size; int reserved_part_blk_num = RESERVED_BLOCK_NUM; + uint8_t bl_mode, base_part = 0; + uint32_t fip_copies, fip_size, fip_part_size = 0; unsigned int bad_blk_addr[128]; mini_part_size = @@ -329,20 +375,39 @@ static int aml_nand_add_partition(struct aml_nand_chip *aml_chip) (1024 * mtd->writesize / aml_chip->plane_num); part_num++; start_blk = 0; - do { - offset = adjust_offset + start_blk * mtd->erasesize; - error = mtd->_block_isbad(mtd, offset); - if (error == FACTORY_BAD_BLOCK_ERROR) { - pr_info("%s:%d factory bad addr =%llx\n", + bl_mode = aml_chip->bl_mode; + if (bl_mode == NAND_FIPMODE_COMPACT) { + /* compact bootloader mode */ + do { + offset = adjust_offset + + start_blk * mtd->erasesize; + error = mtd->_block_isbad(mtd, offset); + if (error == FACTORY_BAD_BLOCK_ERROR) { + pr_info("%s:%d factory bad addr =%llx\n", __func__, __LINE__, (uint64_t)(offset >> phys_erase_shift)); - adjust_offset += mtd->erasesize; - continue; - } - start_blk++; - } while (start_blk < reserved_part_blk_num); - adjust_offset += reserved_part_blk_num * mtd->erasesize; - + adjust_offset += mtd->erasesize; + continue; + } + start_blk++; + } while (start_blk < reserved_part_blk_num); + } else { + /* descrete bootloader mode */ + /* calculate fip partition by dts config*/ + fip_copies = aml_chip->fip_copies; + fip_size = aml_chip->fip_size; + fip_part_size = fip_copies * fip_size; + temp_parts = parts; + /* TODO: do name check! */ + temp_parts->offset = adjust_offset + + reserved_part_blk_num * mtd->erasesize; + temp_parts->size = fip_part_size; + pr_info("%s: off %lld, size %lld\n", temp_parts->name, + temp_parts->offset, temp_parts->size); + base_part = 1; + } + adjust_offset += reserved_part_blk_num * mtd->erasesize + +fip_part_size; /*normal mtd device divide part from here(adjust_offset)*/ if (nr == 0) { part_save_in_env = 0; @@ -357,7 +422,7 @@ static int aml_nand_add_partition(struct aml_nand_chip *aml_chip) mini_part_size = (mtd->erasesize > MINI_PART_SIZE) ? mtd->erasesize : MINI_PART_SIZE; } - for (i = 0; i < nr; i++) { + for (i = base_part; i < nr; i++) { temp_parts = parts + i; bad_block_cnt = 0; memset((u8 *)bad_blk_addr, 0xff, 128 * sizeof(int)); @@ -2311,6 +2376,7 @@ int aml_nand_init(struct aml_nand_chip *aml_chip) struct new_tech_nand_t *new_nand_info = &aml_chip->new_nand_info; struct aml_nand_read_retry *nand_read_retry; struct aml_nand_slc_program *slc_program_info; + /*#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 13)*/ #if 0 struct nand_oobfree *oobfree = NULL; @@ -2356,6 +2422,9 @@ int aml_nand_init(struct aml_nand_chip *aml_chip) aml_chip->aml_nand_hw_init(aml_chip); aml_chip->toggle_mode = 0; + aml_chip->bch_info = NAND_ECC_BCH60_1K; + if (get_cpu_type() == MESON_CPU_MAJOR_ID_AXG) + aml_chip->bch_info = NAND_ECC_BCH8_1K; if (nand_scan(mtd, controller->chip_num) == 0) { chip->options = 0; chip->options |= NAND_SKIP_BBTSCAN; diff --git a/drivers/amlogic/mtd/boot.c b/drivers/amlogic/mtd/boot.c new file mode 100644 index 000000000000..347e72620d8a --- /dev/null +++ b/drivers/amlogic/mtd/boot.c @@ -0,0 +1,1043 @@ +/* + * drivers/amlogic/mtd/boot.c + * + * Copyright (C) 2017 Amlogic, 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. + * + */ + +#include +#include +#include +#include +#ifndef AML_NAND_UBOOT +#include +#include +#endif + +#include "aml_mtd.h" +static DEFINE_MUTEX(boot_mutex); + +#if 0 +#ifndef AML_NAND_UBOOT +struct device *devp; +struct cdev uboot_cdev; +static dev_t uboot_devno; +static struct aml_nand_chip *aml_chip_uboot; +#endif +#endif +/*provide a policy that calculate the backup number of bootloader*/ +static int __attribute__((unused)) get_boot_num( + struct mtd_info *mtd, size_t rwsize) +{ + struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + size_t bad_blk_len_low = 0, bad_blk_len_up = 0, skip; + size_t aviable_space; + loff_t offset = 0; + int ret = 1, error = 0; /*initial for only one copy*/ + + if (!rwsize) { /*not need to policy call, only one */ + ret = 1; + return ret; + } + + while (offset < mtd->size) { + error = mtd->_block_isbad(mtd, offset); + if (error != 0) { + if (offset < mtd->size / 2) + bad_blk_len_low += mtd->erasesize; + else if (offset > mtd->size / 2) + bad_blk_len_up += mtd->erasesize; + else + bad_blk_len_up = offset; + } + offset += mtd->erasesize; + } + + pr_info("rwsize:0x%zx skip_low:0x%zx skip_up:0x%zx\n", + rwsize, bad_blk_len_low, bad_blk_len_up); + + skip = bad_blk_len_low + bad_blk_len_up; + aviable_space = mtd->size - skip - 2 * mtd->writesize; + + if (rwsize*2 <= aviable_space) { + ret = 1; + if (rwsize + mtd->writesize + bad_blk_len_low > mtd->size / 2) + return 1; /*1st must be write*/ + if (rwsize + mtd->writesize + bad_blk_len_up <= mtd->size / 2) + ret++; + } else /*needn't consider bad block length, unlikly so many bad blocks*/ + ret = 1; + + aml_chip->boot_copy_num = ret; + pr_info("copy number:%d\n", ret); + + return ret; +} +/* + * set nand info into page0_buf for romboot. + */ +void __attribute__((unused)) nand_info_page_prepare( + struct aml_nand_chip *aml_chip, + u8 *page0_buf) +{ + struct nand_chip *chip = &aml_chip->chip; + struct mtd_info *mtd = aml_chip->mtd; + struct aml_nand_chip *aml_chip_normal; + int nand_read_info; + u32 configure_data; + struct _nand_page0 *p_nand_page0 = NULL; + struct _ext_info *p_ext_info = NULL; + struct _fip_info *p_fip_info = NULL; + struct nand_setup *p_nand_setup = NULL; + int each_boot_pages, boot_num, bbt_pages; + uint32_t pages_per_blk_shift, bbt_size; + + pages_per_blk_shift = (chip->phys_erase_shift - chip->page_shift); + aml_chip_normal = mtd_to_nand_chip(nand_info[1]); + bbt_size = aml_chip_normal->aml_nandbbt_info->size; + if (aml_chip->bl_mode) { + boot_num = aml_chip->fip_copies; + each_boot_pages = aml_chip->fip_size / mtd->writesize; + } else { + boot_num = (!aml_chip->boot_copy_num) ? + 1 : aml_chip->boot_copy_num; + each_boot_pages = BOOT_TOTAL_PAGES/boot_num; + } + + p_nand_page0 = (struct _nand_page0 *) page0_buf; + p_nand_setup = &p_nand_page0->nand_setup; + p_ext_info = &p_nand_page0->ext_info; + p_fip_info = &p_nand_page0->fip_info; + + configure_data = NFC_CMD_N2M(aml_chip->ran_mode, + aml_chip->bch_mode, 0, (chip->ecc.size >> 3), + chip->ecc.steps); + /* en_slc mode will not be used on slc */ + /* en_slc = 0; */ + + memset(p_nand_page0, 0x0, sizeof(struct _nand_page0)); + /* info_cfg->ext = (configure_data | (1<<23) |(1<<22) | (2<<20)); */ + /* + *p_nand_setup->cfg.d32 = + *(configure_data|(1<<23) | (1<<22) | (2<<20) | (1<<19)); + **/ + /* randomizer mode depends on chip's cofig */ + p_nand_setup->cfg.d32 = (configure_data|(1<<23) | (1<<22) | (2<<20)); + pr_info("cfg.d32 0x%x\n", p_nand_setup->cfg.d32); + /* need finish here for romboot retry */ + p_nand_setup->id = 0; + p_nand_setup->max = 0; + + memset(p_nand_page0->page_list, + 0, + NAND_PAGELIST_CNT); + /* chip_num occupy the lowest 2 bit */ + nand_read_info = controller->chip_num; + + p_ext_info->read_info = nand_read_info; + p_ext_info->page_per_blk = aml_chip->block_size / aml_chip->page_size; + /* fixme, only ce0 is enabled! */ + p_ext_info->ce_mask = 0x01; + /* xlc is not in using for now */ + p_ext_info->xlc = 1; + p_ext_info->boot_num = boot_num; + p_ext_info->each_boot_pages = each_boot_pages; + bbt_pages = + (bbt_size + mtd->writesize - 1) / mtd->writesize; + p_ext_info->bbt_occupy_pages = bbt_pages; + p_ext_info->bbt_start_block = + (BOOT_TOTAL_PAGES >> pages_per_blk_shift) + 4; + /* fill descrete infos */ + if (aml_chip->bl_mode) { + p_fip_info->version = 1; + p_fip_info->mode = NAND_FIPMODE_DISCRETE; + p_fip_info->fip_start = + 1024 + RESERVED_BLOCK_NUM * p_ext_info->page_per_blk; + pr_info("ver %d, mode %d, fip 0x%x\n", + p_fip_info->version, p_fip_info->mode, + p_fip_info->fip_start); + } + /* pr_info("new_type = 0x%x\n", p_ext_info->new_type); */ + pr_info("page_per_blk = 0x%x, bbt_pages 0x%x\n", + p_ext_info->page_per_blk, bbt_pages); + pr_info("boot_num = %d each_boot_pages = %d\n", boot_num, + each_boot_pages); +} + +/* mtd support interface: + * function:int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); + */ +int m3_nand_boot_erase_cmd(struct mtd_info *mtd, int page) +{ + struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + struct nand_chip *chip = mtd->priv; + loff_t ofs; + + ofs = (page << chip->page_shift); + + if (chip->block_bad(mtd, ofs)) + return -1; + + aml_chip->aml_nand_select_chip(aml_chip, 0); + aml_chip->aml_nand_command(aml_chip, + NAND_CMD_ERASE1, -1, page, 0); + aml_chip->aml_nand_command(aml_chip, + NAND_CMD_ERASE2, -1, -1, 0); + chip->waitfunc(mtd, chip); + + return 0; +} + +/* mtd support interface: + * chip->ecc.read_page + * function:int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, + * uint8_t *buf, int oob_required, int page); + */ +int m3_nand_boot_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +{ + struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + uint8_t *oob_buf = chip->oob_poi; + uint32_t nand_page_size = chip->ecc.steps * chip->ecc.size; + uint32_t pages_per_blk_shift = + chip->phys_erase_shift - chip->page_shift; + int user_byte_num = (chip->ecc.steps * aml_chip->user_byte_mode); + int bch_mode = aml_chip->bch_mode, ran_mode = 0; + int error = 0, i = 0, stat = 0; + int ecc_size, configure_data_w, pages_per_blk_w, configure_data; + int pages_per_blk, read_page; + int en_slc = 0; + /* using info page structure */ + struct _nand_page0 *p_nand_page0 = NULL; + struct _ext_info *p_ext_info = NULL; + struct nand_setup *p_nand_setup = NULL; + int each_boot_pages, boot_num; + loff_t ofs; + + u8 type = aml_chip->new_nand_info.type; + + if (aml_chip->support_new_nand == 1) + en_slc = ((type < 10) && type) ? 1:0; + if (aml_chip->bl_mode) + boot_num = 4; + else + boot_num = (!aml_chip->boot_copy_num) ? + 1 : aml_chip->boot_copy_num; + each_boot_pages = BOOT_TOTAL_PAGES / boot_num; + if (page >= (each_boot_pages * boot_num)) { + memset(buf, 0, (1 << chip->page_shift)); + pr_info("nand boot read out of uboot failed, page:%d\n", page); + goto exit; + } + /* nand page info */ + if ((page % each_boot_pages) == 0) { + if (aml_chip->bch_mode == NAND_ECC_BCH_SHORT) + configure_data_w = + NFC_CMD_N2M(aml_chip->ran_mode, + NAND_ECC_BCH60_1K, 1, (chip->ecc.size >> 3), chip->ecc.steps); + else + configure_data_w = + NFC_CMD_N2M(aml_chip->ran_mode, + aml_chip->bch_mode, 0, (chip->ecc.size >> 3), chip->ecc.steps); + + ecc_size = chip->ecc.size; /* backup ecc size */ + + if (aml_chip->bch_mode != NAND_ECC_BCH_SHORT) { + nand_page_size = + (mtd->writesize / 512) * NAND_ECC_UNIT_SHORT; + bch_mode = NAND_ECC_BCH_SHORT; + chip->ecc.size = NAND_ECC_UNIT_SHORT; + } else + bch_mode = aml_chip->bch_mode; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + memset(buf, 0xff, (1 << chip->page_shift)); + /* read back page0 and check it */ + if (aml_chip->valid_chip[0]) { + if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) { + pr_info("don't found selected chip:%d ready\n", + i); + error = -EBUSY; + } + if (aml_chip->ops_mode & AML_CHIP_NONE_RB) + chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + if (en_slc == 0) { + ran_mode = aml_chip->ran_mode; + aml_chip->ran_mode = 1; + } + error = aml_chip->aml_nand_dma_read(aml_chip, + buf, nand_page_size, bch_mode); + if (en_slc == 0) + aml_chip->ran_mode = ran_mode; + if (error) + pr_info(" page0 aml_nand_dma_read failed\n"); + + aml_chip->aml_nand_get_user_byte(aml_chip, + oob_buf, user_byte_num); + stat = aml_chip->aml_nand_hwecc_correct(aml_chip, + buf, nand_page_size, oob_buf); + if (stat < 0) { + mtd->ecc_stats.failed++; + pr_info("page0 read ecc fail at blk0 chip0\n"); + } else + mtd->ecc_stats.corrected += stat; + } else { + pr_info("nand boot page 0 no valid chip failed\n"); + error = -ENODEV; + /* goto exit; */ + } + + /* check page 0 info here */ + p_nand_page0 = (struct _nand_page0 *) buf; + p_nand_setup = &p_nand_page0->nand_setup; + p_ext_info = &p_nand_page0->ext_info; + + configure_data = p_nand_setup->cfg.b.cmd; + pages_per_blk = p_ext_info->page_per_blk; + pages_per_blk_w = + (1 << (chip->phys_erase_shift - chip->page_shift)); + + if ((pages_per_blk_w != pages_per_blk) + || (configure_data != configure_data_w)) { + pr_info("page%d fail ", page); + pr_info("configure:0x%x-0x%x pages_per_blk:0x%x-0x%x\n", + configure_data_w, configure_data, + pages_per_blk_w, pages_per_blk); + } + + bch_mode = aml_chip->bch_mode; + chip->ecc.size = ecc_size; + nand_page_size = chip->ecc.steps * chip->ecc.size; + } + + read_page = page; + read_page++; +READ_BAD_BLOCK: + ofs = (read_page << chip->page_shift); + if (!(ofs % mtd->erasesize)) { + if (chip->block_bad(mtd, ofs)) { + read_page += + 1 << (chip->phys_erase_shift-chip->page_shift); + goto READ_BAD_BLOCK; + } + } + + if (aml_chip->support_new_nand == 1) { + if (en_slc) { + read_page = page % each_boot_pages; + if (type == HYNIX_1YNM_8GB) + read_page = + pagelist_1ynm_hynix256_mtd[read_page + 1] + + (page / each_boot_pages) * each_boot_pages; + else + read_page = + pagelist_hynix256[read_page + 1] + + (page / each_boot_pages) * + each_boot_pages; + } + } + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, read_page); + + memset(buf, 0xff, (1 << chip->page_shift)); + if (aml_chip->valid_chip[0]) { + if (!aml_chip->aml_nand_wait_devready(aml_chip, 0)) { + pr_info("don't found selected chip0 ready, page: %d\n", + page); + error = -EBUSY; + goto exit; + } + if (aml_chip->ops_mode & AML_CHIP_NONE_RB) + chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + error = aml_chip->aml_nand_dma_read(aml_chip, + buf, nand_page_size, bch_mode); + if (error) { + error = -ENODEV; + pr_info("aml_nand_dma_read failed: page:%d\n", page); + goto exit; + } + + aml_chip->aml_nand_get_user_byte(aml_chip, + oob_buf, user_byte_num); + stat = aml_chip->aml_nand_hwecc_correct(aml_chip, + buf, nand_page_size, oob_buf); + if (stat < 0) { + error = -ENODEV; + mtd->ecc_stats.failed++; + pr_info("read data ecc failed at page%d blk%d chip%d\n", + page, (page >> pages_per_blk_shift), i); + } else + mtd->ecc_stats.corrected += stat; + } else + error = -ENODEV; + +exit: + return error; +} + +/* mtd support interface: + * chip->ecc.write_page + * function:int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + * uint8_t *buf, int oob_required, int page); + */ +int m3_nand_boot_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) +{ + struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + uint8_t *oob_buf = chip->oob_poi; + uint32_t nand_page_size = chip->ecc.steps * chip->ecc.size; + int user_byte_num = (chip->ecc.steps * aml_chip->user_byte_mode); + int error = 0, i = 0, bch_mode, ecc_size; + int each_boot_pages, boot_num; + + if (aml_chip->bl_mode) + boot_num = 4; + else + boot_num = (!aml_chip->boot_copy_num) ? + 1 : aml_chip->boot_copy_num; + each_boot_pages = BOOT_TOTAL_PAGES / boot_num; + ecc_size = chip->ecc.size; + if (((aml_chip->page_addr % each_boot_pages) == 0) + && (aml_chip->bch_mode != NAND_ECC_BCH_SHORT)) { + nand_page_size = (mtd->writesize / 512) * NAND_ECC_UNIT_SHORT; + bch_mode = NAND_ECC_BCH_SHORT; + chip->ecc.size = NAND_ECC_UNIT_SHORT; + } else + bch_mode = aml_chip->bch_mode; + /* setting magic for romboot checks. */ + for (i = 0; i < mtd->oobavail; i += 2) { + oob_buf[i] = 0x55; + oob_buf[i+1] = 0xaa; + } + + i = 0; + if (aml_chip->valid_chip[i]) { + aml_chip->aml_nand_select_chip(aml_chip, i); + aml_chip->aml_nand_set_user_byte(aml_chip, + oob_buf, user_byte_num); + error = aml_chip->aml_nand_dma_write(aml_chip, + (unsigned char *)buf, nand_page_size, bch_mode); + if (error) + goto exit; + aml_chip->aml_nand_command(aml_chip, + NAND_CMD_PAGEPROG, -1, -1, i); + } else { + error = -ENODEV; + goto exit; + } +exit: + if (((aml_chip->page_addr % each_boot_pages) == 0) + && (aml_chip->bch_mode != NAND_ECC_BCH_SHORT)) + chip->ecc.size = ecc_size; + return error; +} + +/* mtd support interface: + * chip->write_page + * function: int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + * uint32_t offset, int data_len, const uint8_t *buf, + * int oob_required, int page, int cached, int raw); + */ + +int m3_nand_boot_write_page(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offset, int data_len, const uint8_t *buf, + int oob_required, int page, int cached, int raw) +{ + struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + int status, write_page, ran_mode = 0; + struct new_tech_nand_t *new_nand_info; + struct aml_nand_slc_program *slc_program_info; + int new_nand_type = 0; + int pages_per_blk; + + unsigned char *fill_buf = NULL; + uint32_t priv_slc_page; + int en_slc = 0, each_boot_pages, boot_num; + u8 type = aml_chip->new_nand_info.type; + loff_t ofs; + + new_nand_info = &aml_chip->new_nand_info; + slc_program_info = &new_nand_info->slc_program_info; + if (aml_chip->bl_mode) + boot_num = 4; + else + boot_num = (!aml_chip->boot_copy_num) ? + 1 : aml_chip->boot_copy_num; + + each_boot_pages = BOOT_TOTAL_PAGES / boot_num; + if (aml_chip->support_new_nand == 1) { + new_nand_type = type; + en_slc = ((type < 10) && type) ? 1 : 0; + if (new_nand_type == HYNIX_1YNM_8GB) { + fill_buf = kzalloc(mtd->writesize, GFP_KERNEL); + if (fill_buf == NULL) { + pr_info("malloc fill buf fail\n"); + return -ENOMEM; + } + memset(fill_buf, 0xff, mtd->writesize); + } + + if (en_slc) { + if (page >= (each_boot_pages/2 - 1)) + return 0; + if (slc_program_info->enter_enslc_mode) + slc_program_info->enter_enslc_mode(mtd); + } else { + if (page >= (each_boot_pages - 1)) + return 0; + } + pages_per_blk = (1<<(chip->phys_erase_shift-chip->page_shift)); + } else { + if (page >= (BOOT_TOTAL_PAGES - 1)) + return 0; + } + + /* actual page to be written */ + write_page = page; + /* zero page of each copy */ + if ((write_page % each_boot_pages) == 0) { + nand_info_page_prepare(aml_chip, + chip->buffers->databuf); + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, write_page); + /* must enable ran_mode for info page */ + if (en_slc == 0) { + ran_mode = aml_chip->ran_mode; + aml_chip->ran_mode = 1; + } + chip->ecc.write_page(mtd, + chip, chip->buffers->databuf, 0, write_page); + if (en_slc == 0) + aml_chip->ran_mode = ran_mode; + + status = chip->waitfunc(mtd, chip); + + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) + status = chip->errstat(mtd, + chip, FL_WRITING, status, write_page); + + if (status & NAND_STATUS_FAIL) { + pr_info("uboot wr 0 page=0x%x, status=0x%x\n", + page, status); + return -EIO; + } + } + /* +1 for skipping nand info page */ + if (en_slc) { + if (aml_chip->support_new_nand == 1) { + if (type == HYNIX_1YNM_8GB) + write_page = + pagelist_1ynm_hynix256_mtd[page + 1]; + else + write_page = + pagelist_hynix256[page + 1]; + } + } else + write_page++; + +WRITE_BAD_BLOCK: + ofs = (write_page << chip->page_shift); + if (!(ofs % mtd->erasesize)) { + if (chip->block_bad(mtd, ofs)) { + write_page += + 1 << (chip->phys_erase_shift-chip->page_shift); + goto WRITE_BAD_BLOCK; + } + } + if (aml_chip->support_new_nand == 1) { + if (new_nand_type == HYNIX_1YNM_8GB) { + if ((page + 1) > 1) + priv_slc_page = + pagelist_1ynm_hynix256_mtd[page]; + else + priv_slc_page = page; + while ((priv_slc_page + 1) < write_page) { + chip->cmdfunc(mtd, + NAND_CMD_SEQIN, + 0x00, ++priv_slc_page); + chip->ecc.write_page_raw(mtd, + chip, fill_buf, 0, priv_slc_page); + chip->waitfunc(mtd, chip); + pr_info("%s, fill page:0x%x\n", + __func__, priv_slc_page); + } + } + } + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, write_page); + + if (unlikely(raw)) + chip->ecc.write_page_raw(mtd, chip, buf, 0, write_page); + else + chip->ecc.write_page(mtd, chip, buf, 0, write_page); + + if (!cached || !(chip->options & NAND_CACHEPRG)) { + status = chip->waitfunc(mtd, chip); + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) + status = chip->errstat(mtd, + chip, FL_WRITING, status, write_page); + if (status & NAND_STATUS_FAIL) { + pr_info("uboot wr page=0x%x, status=0x%x\n", + page, status); + if (aml_chip->support_new_nand == 1) { + if (en_slc && slc_program_info->exit_enslc_mode) + slc_program_info->exit_enslc_mode(mtd); + } + return -EIO; + } + } else + status = chip->waitfunc(mtd, chip); + + if (aml_chip->support_new_nand == 1) { + if (en_slc && slc_program_info->exit_enslc_mode) + slc_program_info->exit_enslc_mode(mtd); + } + return 0; +} + +/* extra char device for bootloader */ +#define AML_CHAR_BOOT_DEV (0) +#if (AML_CHAR_BOOT_DEV) +int erase_bootloader(struct mtd_info *mtd, int boot_num) +{ + struct nand_chip *chip = mtd->priv; + struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); + int page, each_boot_pages, boot_copy_num; + int pages_per_block; + int start_page, end_page; + int status; + + if (aml_chip->bl_mode) + boot_copy_num = 4; + else + boot_copy_num = (!aml_chip_uboot->boot_copy_num) ? + 1 : aml_chip_uboot->boot_copy_num; + each_boot_pages = BOOT_TOTAL_PAGES/boot_copy_num; + + nand_get_device(mtd, FL_ERASING); + /* Calculate start page and end page */ + start_page = boot_num * each_boot_pages; + end_page = start_page + each_boot_pages; + + /* Calculate pages in each block */ + pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); + chip->select_chip(mtd, 0);/*fixit, chipnr is set 0 */ + for (page = start_page; page < end_page; page += pages_per_block) { + chip->erase_cmd(mtd, page & chip->pagemask); + pr_info("%s: finish erase page 0x%08x\n", + __func__, page & chip->pagemask); + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + pr_info("%s: failed erase, page 0x%08x\n", + __func__, page & chip->pagemask); + } + chip->select_chip(mtd, -1); + nand_release_device(mtd); + return 0; +} + +/* + * Data structure to carry mtd + */ +struct uboot_file_info { + struct mtd_info *mtd; + int bootsize; + int bootnum; +}; + +static int uboot_open(struct inode *inode, struct file *filp) +{ + struct uboot_file_info *ufi; + struct mtd_info *mtd; + int minor = iminor(inode); + int devnum = minor >> 1; + + mutex_lock(&boot_mutex); + mtd = get_mtd_device(NULL, devnum); + if (IS_ERR(mtd)) + return PTR_ERR(mtd); + + ufi = kzalloc(sizeof(struct uboot_file_info), GFP_KERNEL); + if (!ufi) + return -ENOMEM; + ufi->mtd = mtd; + filp->private_data = ufi; + mutex_unlock(&boot_mutex); + return 0; +} + +static loff_t uboot_llseek(struct file *file, loff_t off, int whence) +{ + loff_t newpos; + struct mtd_info *mtd = &aml_chip_uboot->mtd; + + switch (whence) { + case 0: /* SEEK_SET (start postion)*/ + newpos = off; + break; + + case 1: /* SEEK_CUR */ + newpos = file->f_pos + off; + break; + + case 2: /* SEEK_END */ + newpos = (loff_t)(BOOT_TOTAL_PAGES * mtd->writesize) - 1; + newpos = newpos - off; + break; + + default: /* can't happen */ + return -EINVAL; + } + + if (newpos < 0) + return -EINVAL; + if (newpos >= (loff_t)(BOOT_TOTAL_PAGES * mtd->writesize)) + return -EINVAL; + + file->f_pos = newpos; + + return newpos; +} + + +/* + * This function reads the u-boot envionment variables. + * The f_pos points directly to the env location. + */ +static ssize_t uboot_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + struct mtd_info *mtd = aml_chip_uboot->mtd; + struct nand_chip *chip = &aml_chip_uboot->chip; + unsigned char *data_buf, *buffer; + int ret, page; + size_t align_count = 0, read_size; + loff_t addr; + int chipnr; + + pr_info("%s %d file->f_pos =0x%llx, 0x%zx\n", + __func__, __LINE__, (uint64_t)*ppos, count); + + if (*ppos >= (loff_t)(BOOT_TOTAL_PAGES * mtd->writesize)) { + pr_err("boot read: data access violation!\n"); + return -EFAULT; + } + align_count = + ((((u32)count + mtd->writesize)-1)/mtd->writesize) + * mtd->writesize; + data_buf = vmalloc(align_count + mtd->writesize); + if (!data_buf) { + pr_info("malloc buf for rom_write failed"); + goto err_exit0; + } + addr = *ppos; + buffer = data_buf; + nand_get_device(mtd, FL_READING); + chipnr = (int)(addr >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + for (read_size = 0; read_size < align_count; + read_size += mtd->writesize) { + while ((addr%mtd->erasesize == 0) + && chip->block_bad(mtd, addr, 0)) + addr += mtd->erasesize; + page = addr >> chip->page_shift; + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + chip->ecc.read_page(mtd, chip, buffer, 0, page); + addr += mtd->writesize; + buffer += mtd->writesize; + } + chip->select_chip(mtd, -1); + nand_release_device(mtd); + ret = copy_to_user(buf, data_buf, count); +err_exit0: + vfree(data_buf); + + return count; +} + +static ssize_t uboot_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct mtd_info *mtd = &aml_chip_uboot->mtd; + struct nand_chip *chip = &aml_chip_uboot->chip; + unsigned char *data_buf, *buffer; + int ret, page; + size_t align_count = 0, write_size; + loff_t addr; + int chipnr; + + pr_info("%s %d file->f_pos =0x%llx\n", + __func__, __LINE__, (uint64_t)*ppos); + if (*ppos >= (loff_t)(BOOT_TOTAL_PAGES * mtd->writesize)) { + pr_err("boot write: data access violation!\n"); + return -EFAULT; + } + + align_count = + ((((u32)count + mtd->writesize)-1)/mtd->writesize) + * mtd->writesize; + pr_info("%s %d 0x%zx %d\n", __func__, __LINE__, + align_count, aml_chip_uboot->boot_copy_num); + data_buf = vmalloc(align_count + mtd->writesize);/*fixme*/ + if (!data_buf) { + pr_info("malloc buf for rom_write failed\n"); + goto err_exit0; + } + memset(data_buf, 0x0, align_count); + if (!aml_chip->bl_mode) { + if (!aml_chip_uboot->boot_copy_num) + get_boot_num(mtd, align_count); + } + + ret = copy_from_user(data_buf, buf, count); + addr = *ppos; + buffer = data_buf; + nand_get_device(mtd, FL_WRITING); + chipnr = (int)(addr >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + for (write_size = 0; write_size < align_count; + write_size += mtd->writesize) { + while ((addr % mtd->erasesize == 0) + && chip->block_bad(mtd, addr, 0)) + addr += mtd->erasesize; + page = addr >> chip->page_shift; + pr_info("%s %d write_size=0x%zx page=0x%x\n", + __func__, __LINE__, write_size, page); + chip->write_page(mtd, chip, 0, 0, buffer, 0, page, 0, 0); + addr += mtd->writesize; + buffer += mtd->writesize; + } + chip->select_chip(mtd, -1); + nand_release_device(mtd); + file->f_pos += align_count; +err_exit0: + vfree(data_buf); + return count; +} + +static int uboot_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static int uboot_suspend(struct device *dev, pm_message_t state) +{ + return 0; +} + +static int uboot_resume(struct device *dev) +{ + return 0; +} + +struct boot_info { + int bootnum; + int bootsize; +}; + +#define BOOT_SET_INFO _IOWR('U', 1, struct boot_info) +#define BOOT_GET_INFO _IOWR('U', 2, struct boot_info) +#define BOOT_ERASE_INFO _IOWR('U', 3, int) + +static int boot_ioctl(struct file *file, u_int cmd, u_long arg) +{ + struct uboot_file_info *ufi = file->private_data; + struct mtd_info *mtd = ufi->mtd; + void __user *argp = (void __user *)arg; + int ret = 0, erase_boot_num = 0; + u_long size; + + pr_debug("boot_ioctl\n"); + + size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; + if (cmd & IOC_IN) { + if (!access_ok(VERIFY_READ, argp, size)) + return -EFAULT; + } + if (cmd & IOC_OUT) { + if (!access_ok(VERIFY_WRITE, argp, size)) + return -EFAULT; + } + switch (cmd) { + case BOOT_SET_INFO: + { + struct boot_info info; + + if (copy_to_user(&info, argp, sizeof(struct boot_info))) + return -EFAULT; + ufi->bootsize = info.bootsize; + ufi->bootnum = info.bootnum; + /*aml_chip_uboot->boot_copy_num = info.boot_num;*/ + /* because bad block, + * need call get_boot_num to get boot copies number + */ + get_boot_num(mtd, ufi->bootsize); + break; + } + case BOOT_GET_INFO: + { + struct boot_info __user *info = argp; + + if (put_user(aml_chip_uboot->boot_copy_num, &(info->bootnum))) + return -EFAULT; + break; + } + case BOOT_ERASE_INFO: + if (copy_to_user(&erase_boot_num, argp, sizeof(int))) + return -EFAULT; + erase_bootloader(mtd, erase_boot_num); + break; + default: + ret = -ENOTTY; + } + return ret; +} + +static long boot_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) +{ + int ret; + + mutex_lock(&boot_mutex); + ret = boot_ioctl(file, cmd, arg); + mutex_unlock(&boot_mutex); + + return ret; +} + +#ifdef CONFIG_COMPAT + +#define BOOT_SET_INFO32 _IOWR('U', 8, struct boot_info) +#define BOOT_GET_INFO32 _IOWR('U', 9, struct boot_info) +#define BOOT_ERASE_INFO32 _IOWR('U', 10, int) + +static long boot_compat_ioctl(struct file *file, uint32_t cmd, + unsigned long arg) +{ + struct uboot_file_info *ufi = file->private_data; + struct mtd_info *mtd = ufi->mtd; + void __user *argp = compat_ptr(arg); + int ret = 0; + + mutex_lock(&boot_mutex); + + switch (cmd) { + case BOOT_SET_INFO32: + { + struct boot_info info; + + if (copy_from_user(&info, argp, sizeof(struct boot_info))) + ret = -EFAULT; + else + aml_chip_uboot->boot_copy_num = info.bootnum; + break; + } + case BOOT_GET_INFO32: + { + struct boot_info __user *info = argp; + + if (put_user(aml_chip_uboot->boot_copy_num, &(info->bootnum))) + ret = -EFAULT; + break; + } + case BOOT_ERASE_INFO32: + { + int erase_boot_num; + + if (copy_from_user(&erase_boot_num, argp, sizeof(int))) + ret = -EFAULT; + else + erase_bootloader(mtd, erase_boot_num); + break; + } + default: + ret = boot_ioctl(file, cmd, (unsigned long)argp); + } + + mutex_unlock(&boot_mutex); + + return ret; +} + +#endif /* CONFIG_COMPAT */ + + +static struct class uboot_class = { + + .name = "bootloader", + .owner = THIS_MODULE, + .suspend = uboot_suspend, + .resume = uboot_resume, +}; + +static const struct file_operations uboot_fops = { + .owner = THIS_MODULE, + .open = uboot_open, + .read = uboot_read, + .write = uboot_write, + .unlocked_ioctl = boot_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = boot_compat_ioctl, +#endif + .llseek = uboot_llseek, + .release = uboot_close, +}; + +int boot_device_register(struct aml_nand_chip *aml_chip) +{ + int ret = 0; + + aml_chip_uboot = aml_chip; + + pr_info("boot device register %d\n", aml_chip_uboot->boot_copy_num); + + aml_chip_uboot->boot_copy_num = 0; + + ret = alloc_chrdev_region(&uboot_devno, 0, 1, "bootloader"); + if (ret < 0) { + pr_info("failed to allocate chrdev."); + goto exit_error0; + } + cdev_init(&uboot_cdev, &uboot_fops); + uboot_cdev.owner = THIS_MODULE; + ret = cdev_add(&uboot_cdev, uboot_devno, 1); + if (ret) { + pr_info("failed to add device."); + goto exit_error0; + } + + ret = class_register(&uboot_class); + if (ret < 0) { + pr_info("class_register(&uboot_class) failed!\n"); + goto exit_error0; + } + + devp = device_create(&uboot_class, + NULL, + uboot_devno, + NULL, + "bootloader"); + if (IS_ERR(devp)) { + pr_info("fail to create node\n"); + ret = PTR_ERR(devp); + goto exit_error0; + } + + return 0; +exit_error0: + return ret; +} +#endif +/* endof file */ diff --git a/drivers/amlogic/mtd/m3_nand.c b/drivers/amlogic/mtd/m3_nand.c index fd5fcf7a4baf..7a107876855d 100644 --- a/drivers/amlogic/mtd/m3_nand.c +++ b/drivers/amlogic/mtd/m3_nand.c @@ -25,15 +25,7 @@ int nand_curr_device = -1; struct hw_controller *controller; -/* extern void nand_release_device(struct mtd_info *mtd); */ - -#define NAND_MAX_DEVICE 4 -struct mtd_info nand_info[NAND_MAX_DEVICE] = { - {0}, - {0}, - {0}, - {0} - }; +struct mtd_info *nand_info[NAND_MAX_DEVICE]; #ifdef CONFIG_MTD_DEVICE static __attribute__((unused)) char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; @@ -271,39 +263,36 @@ static void m3_nand_select_chip(struct aml_nand_chip *aml_chip, int chipnr) void get_sys_clk_rate_mtd(struct hw_controller *controller, int *rate) { int clk_freq = *rate; + unsigned int always_on = 0x1 << 24; + unsigned int clk; #ifdef AML_NAND_UBOOT cpu_id_t cpu_id = get_cpu_id(); - if ((cpu_id.family_id == MESON_CPU_MAJOR_ID_GXBB) - || (cpu_id.family_id == MESON_CPU_MAJOR_ID_GXL)) { + if (cpu_id.family_id == MESON_CPU_MAJOR_ID_AXG) #else - if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) - || (get_cpu_type() == MESON_CPU_MAJOR_ID_GXL)) { + if (get_cpu_type() == MESON_CPU_MAJOR_ID_AXG) + always_on = 0x1 << 28; #endif - /* basic debug code using 24Mhz, fixme. */ - if (clk_freq == 24) { - /* 24Mhz/1 = 24Mhz */ - amlnf_write_reg32(controller->nand_clk_reg, 0x81000201); - } else if (clk_freq == 200) { - /* 1000Mhz/5 = 200Mhz */ - amlnf_write_reg32(controller->nand_clk_reg, 0x81000245); - pr_info("%s() %d, clock setting 200!\n", - __func__, __LINE__); - } else if (clk_freq == 250) { - /* 1000Mhz/4 = 250Mhz */ - amlnf_write_reg32(controller->nand_clk_reg, 0x81000244); - pr_info("%s() %d, clock setting 250!\n", - __func__, __LINE__); - } else { - /* 1000Mhz/5 = 200Mhz */ - amlnf_write_reg32(controller->nand_clk_reg, 0x81000245); - pr_info("%s() %d, using default clock 200MHz !\n", - __func__, __LINE__); + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) + || (get_cpu_type() == MESON_CPU_MAJOR_ID_GXL) + || (get_cpu_type() == MESON_CPU_MAJOR_ID_AXG)) { + switch (clk_freq) { + case 24: + clk = 0x80000201; + break; + case 200: + clk = 0x80000245; + break; + case 250: + clk = 0x80000244; + break; + default: + clk = 0x80000245; + break; } - /* - *pr_info("clk_reg 0x%x\n", - * AMLNF_READ_REG(controller->nand_clk_reg)); - **/ + clk |= always_on; + amlnf_write_reg32(controller->nand_clk_reg, clk); + return; } else pr_info("%s %d: not support cpu type!!!\n", __func__, __LINE__); @@ -662,7 +651,7 @@ static int m3_nand_dma_write(struct aml_nand_chip *aml_chip, NFC_SEND_CMD_M2N_RAW(controller, 0, len); else NFC_SEND_CMD_M2N(controller, aml_chip->ran_mode, - ((bch_mode == NAND_ECC_BCH_SHORT) ? NAND_ECC_BCH60_1K : bch_mode), + ((bch_mode == NAND_ECC_BCH_SHORT) ? aml_chip->bch_info : bch_mode), ((bch_mode == NAND_ECC_BCH_SHORT) ? 1 : 0), dma_unit_size, count); ret = aml_platform_dma_waiting(aml_chip); @@ -737,7 +726,7 @@ static int m3_nand_dma_read(struct aml_nand_chip *aml_chip, NFC_SEND_CMD_N2M_RAW(controller, 0, len); else NFC_SEND_CMD_N2M(controller, aml_chip->ran_mode, - ((bch_mode == NAND_ECC_BCH_SHORT)?NAND_ECC_BCH60_1K:bch_mode), + ((bch_mode == NAND_ECC_BCH_SHORT)?aml_chip->bch_info:bch_mode), ((bch_mode == NAND_ECC_BCH_SHORT)?1:0), dma_unit_size, count); ret = aml_platform_dma_waiting(aml_chip); @@ -799,474 +788,6 @@ static int m3_nand_hwecc_correct(struct aml_nand_chip *aml_chip, return 0; } -static int m3_nand_boot_erase_cmd(struct mtd_info *mtd, int page) -{ - struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); - struct nand_chip *chip = mtd->priv; - loff_t ofs; - int i, page_addr; - - if (page >= BOOT_PAGES_PER_COPY) - return -EPERM; - - if (aml_chip->valid_chip[0]) { - for (i = 0; i < BOOT_COPY_NUM; i++) { - page_addr = page + i*BOOT_PAGES_PER_COPY; - ofs = (page_addr << chip->page_shift); - - if (chip->block_bad(mtd, ofs)) - continue; - - aml_chip->aml_nand_select_chip(aml_chip, 0); - aml_chip->aml_nand_command(aml_chip, - NAND_CMD_ERASE1, -1, page_addr, 0); - aml_chip->aml_nand_command(aml_chip, - NAND_CMD_ERASE2, -1, -1, 0); - chip->waitfunc(mtd, chip); - } - } - - return 0; -} - -static int m3_nand_boot_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); - uint8_t *oob_buf = chip->oob_poi; - unsigned int nand_page_size = chip->ecc.steps * chip->ecc.size; - uint32_t pages_per_blk_shift = chip->phys_erase_shift-chip->page_shift; - int user_byte_num = (chip->ecc.steps * aml_chip->user_byte_mode); - int bch_mode = aml_chip->bch_mode, ran_mode = 0; - int error = 0, i = 0, stat = 0; - int ecc_size, configure_data_w, pages_per_blk_w, configure_data; - int pages_per_blk, read_page; - int en_slc = 0; - /* using info page structure */ - struct _nand_page0 *p_nand_page0 = NULL; - struct _ext_info *p_ext_info = NULL; - struct nand_setup *p_nand_setup = NULL; - u8 type = aml_chip->new_nand_info.type; - - if (aml_chip->support_new_nand == 1) - en_slc = ((type < 10) && type) ? 1:0; - - if (page >= (BOOT_PAGES_PER_COPY*BOOT_COPY_NUM)) { - memset(buf, 0, (1 << chip->page_shift)); - pr_info("nand boot read out of uboot failed, page:%d\n", page); - goto exit; - } - /* nand page info */ - if ((page % BOOT_PAGES_PER_COPY) == 0) { - if (aml_chip->bch_mode == NAND_ECC_BCH_SHORT) - configure_data_w = - NFC_CMD_N2M(aml_chip->ran_mode, - NAND_ECC_BCH60_1K, 1, (chip->ecc.size >> 3), chip->ecc.steps); - else - configure_data_w = - NFC_CMD_N2M(aml_chip->ran_mode, - aml_chip->bch_mode, 0, (chip->ecc.size >> 3), chip->ecc.steps); - - ecc_size = chip->ecc.size; /* backup ecc size */ - - if (aml_chip->bch_mode != NAND_ECC_BCH_SHORT) { - nand_page_size = - (mtd->writesize / 512) * NAND_ECC_UNIT_SHORT; - bch_mode = NAND_ECC_BCH_SHORT; - chip->ecc.size = NAND_ECC_UNIT_SHORT; - } else - bch_mode = aml_chip->bch_mode; - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - memset(buf, 0xff, (1 << chip->page_shift)); - /* read back page0 and check it */ - if (aml_chip->valid_chip[0]) { - if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) { - pr_info("don't found selected chip:%d ready\n", - i); - error = -EBUSY; - } - if (aml_chip->ops_mode & AML_CHIP_NONE_RB) - chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - if (en_slc == 0) { - ran_mode = aml_chip->ran_mode; - aml_chip->ran_mode = 1; - } - error = aml_chip->aml_nand_dma_read(aml_chip, - buf, nand_page_size, bch_mode); - if (en_slc == 0) - aml_chip->ran_mode = ran_mode; - if (error) - pr_info(" page0 aml_nand_dma_read failed\n"); - - aml_chip->aml_nand_get_user_byte(aml_chip, - oob_buf, user_byte_num); - stat = aml_chip->aml_nand_hwecc_correct(aml_chip, - buf, nand_page_size, oob_buf); - if (stat < 0) { - mtd->ecc_stats.failed++; - pr_info("page0 read ecc fail at blk0 chip0\n"); - } else - mtd->ecc_stats.corrected += stat; - } else { - pr_info("nand boot page 0 no valid chip failed\n"); - error = -ENODEV; - /* goto exit; */ - } - - /* check page 0 info here */ - p_nand_page0 = (struct _nand_page0 *) buf; - p_nand_setup = &p_nand_page0->nand_setup; - p_ext_info = &p_nand_page0->ext_info; - - configure_data = p_nand_setup->cfg.b.cmd; - pages_per_blk = p_ext_info->page_per_blk; - pages_per_blk_w = - (1 << (chip->phys_erase_shift - chip->page_shift)); - - if ((pages_per_blk_w != pages_per_blk) - || (configure_data != configure_data_w)) { - pr_info("page%d fail ", page); - pr_info("configure:0x%x-0x%x pages_per_blk:0x%x-0x%x\n", - configure_data_w, configure_data, - pages_per_blk_w, pages_per_blk); - } - - bch_mode = aml_chip->bch_mode; - chip->ecc.size = ecc_size; - nand_page_size = chip->ecc.steps * chip->ecc.size; - } - - read_page = page; - read_page++; - if (aml_chip->support_new_nand == 1) { - if (en_slc) { - read_page = page % BOOT_PAGES_PER_COPY; - if (type == HYNIX_1YNM_8GB) - read_page = - pagelist_1ynm_hynix256_mtd[read_page + 1] + - (page / BOOT_PAGES_PER_COPY) * BOOT_PAGES_PER_COPY; - else - read_page = - pagelist_hynix256[read_page + 1] + - (page / BOOT_PAGES_PER_COPY)*BOOT_PAGES_PER_COPY; - } - } - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, read_page); - - memset(buf, 0xff, (1 << chip->page_shift)); - if (aml_chip->valid_chip[0]) { - if (!aml_chip->aml_nand_wait_devready(aml_chip, 0)) { - pr_info("don't found selected chip0 ready, page: %d\n", - page); - error = -EBUSY; - goto exit; - } - if (aml_chip->ops_mode & AML_CHIP_NONE_RB) - chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - - error = aml_chip->aml_nand_dma_read(aml_chip, - buf, nand_page_size, bch_mode); - if (error) { - error = -ENODEV; - pr_info("aml_nand_dma_read failed: page:%d\n", page); - goto exit; - } - - aml_chip->aml_nand_get_user_byte(aml_chip, - oob_buf, user_byte_num); - stat = aml_chip->aml_nand_hwecc_correct(aml_chip, - buf, nand_page_size, oob_buf); - if (stat < 0) { - error = -ENODEV; - mtd->ecc_stats.failed++; - pr_info("read data ecc failed at blk%d chip%d\n", - (page >> pages_per_blk_shift), i); - } else - mtd->ecc_stats.corrected += stat; - } else - error = -ENODEV; - -exit: - return error; -} - -/* - * set nand info into page0_buf for romboot. - */ -void __attribute__((unused)) nand_info_page_prepare( - struct aml_nand_chip *aml_chip, - u8 *page0_buf) -{ - struct nand_chip *chip = &aml_chip->chip; - /* fixme, - *devops_len = devops->len which means the total operation of uboot - **/ - u32 devops_len = (BOOT_PAGES_PER_COPY-1) * aml_chip->page_size; - /* struct hw_controller *controller = &(aml_chip->controller); */ - int i, nand_read_info; - u32 en_slc, configure_data; - u32 boot_num = 1, each_boot_pages; - u32 valid_pages = BOOT_TOTAL_PAGES; - - struct _nand_page0 *p_nand_page0 = NULL; - struct _ext_info *p_ext_info = NULL; - struct nand_setup *p_nand_setup = NULL; - - p_nand_page0 = (struct _nand_page0 *) page0_buf; - p_nand_setup = &p_nand_page0->nand_setup; - p_ext_info = &p_nand_page0->ext_info; - - - configure_data = NFC_CMD_N2M(aml_chip->ran_mode, - aml_chip->bch_mode, 0, (chip->ecc.size >> 3), - chip->ecc.steps); - /* en_slc mode will not be used on slc */ - en_slc = 0; - - memset(p_nand_page0, 0x0, sizeof(struct _nand_page0)); - /* info_cfg->ext = (configure_data | (1<<23) |(1<<22) | (2<<20)); */ - /* - *p_nand_setup->cfg.d32 = - *(configure_data|(1<<23) | (1<<22) | (2<<20) | (1<<19)); - **/ - /* randomizer mode depends on chip's cofig */ - p_nand_setup->cfg.d32 = (configure_data|(1<<23) | (1<<22) | (2<<20)); - pr_info("cfg.d32 0x%x\n", p_nand_setup->cfg.d32); - /* need finish here for romboot retry */ - p_nand_setup->id = 0; - p_nand_setup->max = 0; - - memset(p_nand_page0->page_list, - 0, - NAND_PAGELIST_CNT); - /* chip_num occupy the lowest 2 bit */ - nand_read_info = controller->chip_num; - - /* - *make it - *1)calu the number of boot saved and pages each boot needs. - *2)the number is 2*n but less than 4. - **/ - pr_info("valid_pages = %d en_slc = %d devops_len = 0x%x", - valid_pages, - en_slc, devops_len); - valid_pages = (en_slc)?(valid_pages>>1):valid_pages; - for (i = 1; - i < ((valid_pages*aml_chip->page_size)/devops_len + 1); i++) { - if (((valid_pages*aml_chip->page_size)/(2*i) >= devops_len) - && (boot_num < 4)) - boot_num <<= 1; - else - break; - } - each_boot_pages = valid_pages/boot_num; - - p_ext_info->read_info = nand_read_info; - p_ext_info->page_per_blk = aml_chip->block_size / aml_chip->page_size; - /* fixme, only ce0 is enabled! */ - p_ext_info->ce_mask = 0x01; - /* xlc is not in using for now */ - p_ext_info->xlc = 1; - p_ext_info->boot_num = boot_num; - p_ext_info->each_boot_pages = each_boot_pages; - - /* pr_info("new_type = 0x%x\n", p_ext_info->new_type); */ - pr_info("page_per_blk = 0x%x\n", p_ext_info->page_per_blk); - pr_info("boot_num = %d each_boot_pages = %d", boot_num, - each_boot_pages); -} - -static int m3_nand_boot_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) -{ - struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); - uint8_t *oob_buf = chip->oob_poi; - unsigned int nand_page_size = chip->ecc.steps * chip->ecc.size; - int user_byte_num = (chip->ecc.steps * aml_chip->user_byte_mode); - int error = 0, i = 0, bch_mode, ecc_size; - - ecc_size = chip->ecc.size; - if (((aml_chip->page_addr % BOOT_PAGES_PER_COPY) == 0) - && (aml_chip->bch_mode != NAND_ECC_BCH_SHORT)) { - nand_page_size = (mtd->writesize / 512) * NAND_ECC_UNIT_SHORT; - bch_mode = NAND_ECC_BCH_SHORT; - chip->ecc.size = NAND_ECC_UNIT_SHORT; - } else - bch_mode = aml_chip->bch_mode; - /* setting magic for romboot checks. */ - for (i = 0; i < mtd->oobavail; i += 2) { - oob_buf[i] = 0x55; - oob_buf[i+1] = 0xaa; - } - - i = 0; - if (aml_chip->valid_chip[i]) { - aml_chip->aml_nand_select_chip(aml_chip, i); - aml_chip->aml_nand_set_user_byte(aml_chip, - oob_buf, user_byte_num); - error = aml_chip->aml_nand_dma_write(aml_chip, - (unsigned char *)buf, nand_page_size, bch_mode); - if (error) - goto exit; - aml_chip->aml_nand_command(aml_chip, - NAND_CMD_PAGEPROG, -1, -1, i); - } else { - error = -ENODEV; - goto exit; - } -exit: - if (((aml_chip->page_addr % BOOT_PAGES_PER_COPY) == 0) - && (aml_chip->bch_mode != NAND_ECC_BCH_SHORT)) - chip->ecc.size = ecc_size; - return error; -} - -static int m3_nand_boot_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) -{ - struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); - int status, i, write_page, ran_mode = 0; - int new_nand_type = 0; - int pages_per_blk; - struct new_tech_nand_t *new_nand_info; - struct aml_nand_slc_program *slc_program_info; - int en_slc = 0; - unsigned char *fill_buf = NULL; - unsigned int priv_slc_page; - u8 type = aml_chip->new_nand_info.type; - - new_nand_info = &aml_chip->new_nand_info; - slc_program_info = &new_nand_info->slc_program_info; - - if (aml_chip->support_new_nand == 1) { - new_nand_type = type; - en_slc = ((type < 10) && type) ? 1 : 0; - if (new_nand_type == HYNIX_1YNM_8GB) { - fill_buf = kzalloc(mtd->writesize, GFP_KERNEL); - if (fill_buf == NULL) { - pr_info("malloc fill buf fail\n"); - return -ENOMEM; - } - memset(fill_buf, 0xff, mtd->writesize); - } - - if (en_slc) { - if (page >= (BOOT_PAGES_PER_COPY/2 - 1)) - return 0; - if (slc_program_info->enter_enslc_mode) - slc_program_info->enter_enslc_mode(mtd); - } else { - if (page >= (BOOT_PAGES_PER_COPY - 1)) - return 0; - } - pages_per_blk = (1<<(chip->phys_erase_shift-chip->page_shift)); - } else { - if (page >= (BOOT_PAGES_PER_COPY - 1)) - return 0; - } - - /* write all copies at 1 time */ - for (i = 0; i < BOOT_COPY_NUM; i++) { - /* actual page to be written */ - write_page = page + i*BOOT_PAGES_PER_COPY; - /* zero page of each copy */ - if ((write_page % BOOT_PAGES_PER_COPY) == 0) { - nand_info_page_prepare(aml_chip, - chip->buffers->databuf); - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, write_page); - /* must enable ran_mode for info page */ - if (en_slc == 0) { - ran_mode = aml_chip->ran_mode; - aml_chip->ran_mode = 1; - } - chip->ecc.write_page(mtd, - chip, chip->buffers->databuf, 0, write_page); - if (en_slc == 0) - aml_chip->ran_mode = ran_mode; - - status = chip->waitfunc(mtd, chip); - - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, - chip, FL_WRITING, status, write_page); - - if (status & NAND_STATUS_FAIL) { - pr_info("uboot wr 0 page=0x%x, status=0x%x\n", - page, status); - return -EIO; - } - } - /* +1 for skipping nand info page */ - if (en_slc) { - if (aml_chip->support_new_nand == 1) { - if (type == HYNIX_1YNM_8GB) - write_page = - pagelist_1ynm_hynix256_mtd[page + 1] + - i*BOOT_PAGES_PER_COPY; - else - write_page = - pagelist_hynix256[page + 1] + - i * BOOT_PAGES_PER_COPY; - } - } else - write_page++; - - if (aml_chip->support_new_nand == 1) { - if (new_nand_type == HYNIX_1YNM_8GB) { - if ((page + 1) > 1) - priv_slc_page = - pagelist_1ynm_hynix256_mtd[page] + - i * BOOT_PAGES_PER_COPY; - else - priv_slc_page = page + - i * BOOT_PAGES_PER_COPY; - while ((priv_slc_page + 1) < write_page) { - chip->cmdfunc(mtd, - NAND_CMD_SEQIN, - 0x00, ++priv_slc_page); - chip->ecc.write_page_raw(mtd, - chip, fill_buf, 0, priv_slc_page); - chip->waitfunc(mtd, chip); - pr_info("%s, fill page:0x%x\n", - __func__, priv_slc_page); - } - } - } - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, write_page); - - if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf, 0, write_page); - else - chip->ecc.write_page(mtd, chip, buf, 0, write_page); - - if (!cached || !(chip->options & NAND_CACHEPRG)) { - status = chip->waitfunc(mtd, chip); - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, - chip, FL_WRITING, status, write_page); - if (status & NAND_STATUS_FAIL) { - pr_info("uboot wr page=0x%x, status=0x%x\n", - page, status); - if (aml_chip->support_new_nand == 1) { - if (en_slc && slc_program_info->exit_enslc_mode) - slc_program_info->exit_enslc_mode(mtd); - } - return -EIO; - } - } else - status = chip->waitfunc(mtd, chip); - } - if (aml_chip->support_new_nand == 1) { - if (en_slc && slc_program_info->exit_enslc_mode) - slc_program_info->exit_enslc_mode(mtd); - } - return 0; -} #ifndef AML_NAND_UBOOT struct nand_hw_control upper_controller; @@ -1331,6 +852,7 @@ static int m3_nand_probe(struct aml_nand_platform *plat, unsigned int dev_num) struct mtd_info *mtd = NULL; int err = 0; unsigned int nand_type = 0; + struct aml_nand_device *aml_nand_device = NULL; /*#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 13)*/ #if 0 int tmp_val, i; @@ -1349,6 +871,7 @@ static int m3_nand_probe(struct aml_nand_platform *plat, unsigned int dev_num) /* initialize mtd info data struct */ aml_chip->controller = controller; + /* to it's own plat data */ aml_chip->platform = plat; aml_chip->bch_desc = m3_bch_list; aml_chip->max_bch_mode = ARRAY_SIZE(m3_bch_list); @@ -1362,6 +885,15 @@ static int m3_nand_probe(struct aml_nand_platform *plat, unsigned int dev_num) #ifndef AML_NAND_UBOOT /*fixit ,hardware support all address*/ /* dev->coherent_dma_mask = DMA_BIT_MASK(32); */ + aml_nand_device = plat->aml_nand_device; + pr_info("%s() aml_nand_device %p\n", __func__, aml_nand_device); + if (aml_nand_device) { + aml_chip->bl_mode = aml_nand_device->bl_mode; + aml_chip->fip_copies = aml_nand_device->fip_copies; + aml_chip->fip_size = aml_nand_device->fip_size; + } + + aml_chip->device = dev; mtd->dev.parent = dev->parent; mtd->owner = THIS_MODULE; @@ -1434,7 +966,7 @@ static int m3_nand_probe(struct aml_nand_platform *plat, unsigned int dev_num) /*need to set device_boot_flag here*/ device_boot_flag = NAND_BOOT_FLAG; #endif - nand_info[dev_num] = *mtd; + nand_info[dev_num] = mtd; return 0; exit_error: @@ -1477,7 +1009,6 @@ void nand_init(void) pr_info("error for not platform data\n"); continue; } - ret = m3_nand_probe(plat, i); if (ret) { pr_info("nand init faile: %d\n", ret); @@ -1529,9 +1060,11 @@ int nand_init(struct platform_device *pdev) dev_err(&pdev->dev, "ioremap Nand Flash IO fail\n"); return -ENOMEM; } + pr_info("nand_clk_ctrl 0x%x\n", + aml_nand_mid_device.nand_clk_ctrl); controller->nand_clk_reg = devm_ioremap_nocache(&pdev->dev, - NAND_CLK_CNTL, + aml_nand_mid_device.nand_clk_ctrl, sizeof(int)); if (controller->nand_clk_reg == NULL) { dev_err(&pdev->dev, "ioremap External Nand Clock IO fail\n"); @@ -1590,6 +1123,9 @@ int nand_init(struct platform_device *pdev) continue; } #ifndef AML_NAND_UBOOT + /* to get the glb fip infos */ + plat->aml_nand_device = &aml_nand_mid_device; + pr_info("plat->aml_nand_device %p\n", plat->aml_nand_device); ret = m3_nand_probe(plat, i, &pdev->dev); #else ret = m3_nand_probe(plat, i); diff --git a/drivers/amlogic/mtd/mtd_driver.c b/drivers/amlogic/mtd/mtd_driver.c index 1e14d5fa83c0..d7373bc5861c 100644 --- a/drivers/amlogic/mtd/mtd_driver.c +++ b/drivers/amlogic/mtd/mtd_driver.c @@ -194,6 +194,38 @@ static int prase_get_dtb_nand_parameter(struct aml_nand_device *aml_nand_dev, of_node_put(np_config); } } + + ret = of_property_read_u32(np, + "bl_mode", (u32 *)&aml_nand_dev->bl_mode); + if (ret) { + pr_info("%s:%d,please config bl_mode item\n", + __func__, __LINE__); + } + pr_info("bl mode %s\n", + aml_nand_dev->bl_mode?"descrete":"compact"); + + ret = of_property_read_u32(np, + "fip_copies", (u32 *)&aml_nand_dev->fip_copies); + if (ret) { + pr_info("%s:%d,please config fip_copies item\n", + __func__, __LINE__); + } + pr_info("fip_copies %d\n", aml_nand_dev->fip_copies); + ret = of_property_read_u32(np, + "fip_size", (u32 *)&aml_nand_dev->fip_size); + pr_info("fip_size 0x%x\n", aml_nand_dev->fip_size); + if (ret) { + pr_info("%s:%d,please config fip_size item\n", + __func__, __LINE__); + } + ret = of_property_read_u32(np, + "nand_clk_ctrl", (u32 *)&aml_nand_dev->nand_clk_ctrl); + pr_info("nand_clk_ctrl 0x%x\n", aml_nand_dev->nand_clk_ctrl); + if (ret) { + aml_nand_dev->nand_clk_ctrl = NAND_CLK_CNTL; + pr_info("%s:%d, using default nand_clk_ctrl 0x%x\n", + __func__, __LINE__, NAND_CLK_CNTL); + } }; pr_info("%s:%d,parse dts end\n", __func__, __LINE__); return 0; diff --git a/drivers/amlogic/mtd/nand_flash.c b/drivers/amlogic/mtd/nand_flash.c index 0af862b816cf..b8b9a84bcd4c 100644 --- a/drivers/amlogic/mtd/nand_flash.c +++ b/drivers/amlogic/mtd/nand_flash.c @@ -1281,7 +1281,7 @@ static int aml_nand_scan_ident(struct mtd_info *mtd, int maxchips) /* overide bootloader's size consdering info page */ if (!strcmp(mtd->name, NAND_BOOT_NAME)) - mtd->size = BOOT_PAGES_PER_COPY * mtd->writesize; + mtd->size = BOOT_TOTAL_PAGES * mtd->writesize; chip->cmdfunc = aml_nand_command; chip->waitfunc = aml_nand_wait; diff --git a/drivers/amlogic/pinctrl/pinctrl-mesonaxg.c b/drivers/amlogic/pinctrl/pinctrl-mesonaxg.c index 0da04a9ef54d..0cbb5b398b9f 100644 --- a/drivers/amlogic/pinctrl/pinctrl-mesonaxg.c +++ b/drivers/amlogic/pinctrl/pinctrl-mesonaxg.c @@ -67,32 +67,40 @@ static const struct meson_desc_pin mesonaxg_periphs_pins[] = { MESON_FUNCTION(0x0, "gpio")), MESON_PINCTRL_PIN(MESON_PIN(BOOT_0, EE_OFF), 0x0, 0, MESON_FUNCTION(0x0, "gpio"), - MESON_FUNCTION(0x1, "emmc")), /*EMMC_D0*/ + MESON_FUNCTION(0x1, "emmc"), /*EMMC_D0*/ + MESON_FUNCTION(0x1, "nandflash")), /*EMMC_D0*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_1, EE_OFF), 0x0, 4, MESON_FUNCTION(0x0, "gpio"), - MESON_FUNCTION(0x1, "emmc")), /*EMMC_D1*/ + MESON_FUNCTION(0x1, "emmc"), + MESON_FUNCTION(0x1, "nandflash")), /*EMMC_D1*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_2, EE_OFF), 0x0, 8, MESON_FUNCTION(0x0, "gpio"), - MESON_FUNCTION(0x1, "emmc")), /*EMMC_D2*/ + MESON_FUNCTION(0x1, "emmc"), + MESON_FUNCTION(0x1, "nandflash")), /*EMMC_D2*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_3, EE_OFF), 0x0, 12, MESON_FUNCTION(0x0, "gpio"), MESON_FUNCTION(0x1, "emmc"), /*EMMC_D3*/ + MESON_FUNCTION(0x1, "nandflash"), MESON_FUNCTION(0x3, "norflash")), /*NOR_HOLD*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_4, EE_OFF), 0x0, 16, MESON_FUNCTION(0x0, "gpio"), MESON_FUNCTION(0x1, "emmc"), /*EMMC_D4*/ + MESON_FUNCTION(0x1, "nandflash"), MESON_FUNCTION(0x3, "norflash")), /*NOR_D*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_5, EE_OFF), 0x0, 20, MESON_FUNCTION(0x0, "gpio"), MESON_FUNCTION(0x1, "emmc"), /*EMMC_D5*/ + MESON_FUNCTION(0x1, "nandflash"), MESON_FUNCTION(0x3, "norflash")), /*NOR_Q*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_6, EE_OFF), 0x0, 24, MESON_FUNCTION(0x0, "gpio"), MESON_FUNCTION(0x1, "emmc"), /*EMMC_D6*/ + MESON_FUNCTION(0x1, "nandflash"), MESON_FUNCTION(0x3, "norflash")), /*NOR_C*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_7, EE_OFF), 0x0, 28, MESON_FUNCTION(0x0, "gpio"), - MESON_FUNCTION(0x1, "emmc")), /*EMMC_D7*/ + MESON_FUNCTION(0x1, "emmc"), + MESON_FUNCTION(0x1, "nandflash")), /*EMMC_D7*/ MESON_PINCTRL_PIN(MESON_PIN(BOOT_8, EE_OFF), 0x1, 0, MESON_FUNCTION(0x0, "gpio"), MESON_FUNCTION(0x1, "emmc"), /*EMMC_CLK*/