802 lines
20 KiB
C
802 lines
20 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* drivers/nand/dev/amlnf_ctrl.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Aml
|
|
*
|
|
* (C) 2012 8
|
|
*/
|
|
#include "../include/phynand.h"
|
|
#include <asm/arch/secure_apb.h>
|
|
#include <asm/cpu_id.h>
|
|
|
|
extern int aml_ubootenv_init(struct amlnand_chip *aml_chip);
|
|
#if (AML_CFG_DTB_RSV_EN)
|
|
extern int amlnf_dtb_init(struct amlnand_chip *aml_chip);
|
|
#endif
|
|
extern int amlnand_save_info_by_name(struct amlnand_chip *aml_chip,unsigned char * info,unsigned char * buf, u8 * name,unsigned size);
|
|
|
|
#ifdef AML_NAND_UBOOT
|
|
struct list_head nf_dev_list;
|
|
struct list_head nlogic_dev_list;
|
|
#endif /* AML_NAND_UBOOT */
|
|
|
|
struct bch_desc bch_list_m8[MAX_ECC_MODE_NUM] = {
|
|
[0] = ECC_INFORMATION("NAND_RAW_MODE",
|
|
NAND_ECC_SOFT_MODE,
|
|
0,
|
|
0,
|
|
0,
|
|
0),
|
|
[1] = ECC_INFORMATION("NAND_BCH8_MODE",
|
|
NAND_ECC_BCH8_MODE,
|
|
NAND_ECC_UNIT_SIZE,
|
|
NAND_BCH8_ECC_SIZE,
|
|
2,
|
|
1),
|
|
[2] = ECC_INFORMATION("NAND_BCH8_1K_MODE" ,
|
|
NAND_ECC_BCH8_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH8_1K_ECC_SIZE,
|
|
2,
|
|
2),
|
|
[3] = ECC_INFORMATION("NAND_BCH24_1K_MODE" ,
|
|
NAND_ECC_BCH24_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH24_1K_ECC_SIZE,
|
|
2,
|
|
3),
|
|
[4] = ECC_INFORMATION("NAND_BCH30_1K_MODE" ,
|
|
NAND_ECC_BCH30_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH30_1K_ECC_SIZE,
|
|
2,
|
|
4),
|
|
[5] = ECC_INFORMATION("NAND_BCH40_1K_MODE" ,
|
|
NAND_ECC_BCH40_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH40_1K_ECC_SIZE,
|
|
2,
|
|
5),
|
|
[6] = ECC_INFORMATION("NAND_BCH50_1K_MODE" ,
|
|
NAND_ECC_BCH50_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH50_1K_ECC_SIZE,
|
|
2,
|
|
6),
|
|
[7] = ECC_INFORMATION("NAND_BCH60_1K_MODE" ,
|
|
NAND_ECC_BCH60_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH60_1K_ECC_SIZE,
|
|
2,
|
|
7),
|
|
[8] = ECC_INFORMATION("NAND_SHORT_MODE" ,
|
|
NAND_ECC_SHORT_MODE,
|
|
NAND_ECC_UNIT_SHORT,
|
|
NAND_BCH60_1K_ECC_SIZE,
|
|
2,
|
|
8),
|
|
};
|
|
|
|
struct bch_desc bch_list[MAX_ECC_MODE_NUM] = {
|
|
[0] = ECC_INFORMATION("NAND_RAW_MODE",
|
|
NAND_ECC_SOFT_MODE,
|
|
0,
|
|
0,
|
|
0,
|
|
0),
|
|
[1] = ECC_INFORMATION("NAND_BCH8_MODE",
|
|
NAND_ECC_BCH8_MODE,
|
|
NAND_ECC_UNIT_SIZE,
|
|
NAND_BCH8_ECC_SIZE,
|
|
2,
|
|
1),
|
|
[2] = ECC_INFORMATION("NAND_BCH8_1K_MODE" ,
|
|
NAND_ECC_BCH8_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH8_1K_ECC_SIZE,
|
|
2,
|
|
2),
|
|
[3] = ECC_INFORMATION("NAND_BCH16_1K_MODE" ,
|
|
NAND_ECC_BCH16_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH16_1K_ECC_SIZE,
|
|
2,
|
|
3),
|
|
[4] = ECC_INFORMATION("NAND_BCH24_1K_MODE" ,
|
|
NAND_ECC_BCH24_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH24_1K_ECC_SIZE,
|
|
2,
|
|
4),
|
|
[5] = ECC_INFORMATION("NAND_BCH30_1K_MODE" ,
|
|
NAND_ECC_BCH30_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH30_1K_ECC_SIZE,
|
|
2,
|
|
5),
|
|
[6] = ECC_INFORMATION("NAND_BCH40_1K_MODE" ,
|
|
NAND_ECC_BCH40_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH40_1K_ECC_SIZE,
|
|
2,
|
|
6),
|
|
[7] = ECC_INFORMATION("NAND_BCH60_1K_MODE" ,
|
|
NAND_ECC_BCH60_1K_MODE,
|
|
NAND_ECC_UNIT_1KSIZE,
|
|
NAND_BCH60_1K_ECC_SIZE,
|
|
2,
|
|
7),
|
|
[8] = ECC_INFORMATION("NAND_SHORT_MODE" ,
|
|
NAND_ECC_SHORT_MODE,
|
|
NAND_ECC_UNIT_SHORT,
|
|
NAND_BCH60_1K_ECC_SIZE,
|
|
2,
|
|
8),
|
|
};
|
|
|
|
|
|
#ifndef AML_NAND_UBOOT
|
|
static dma_addr_t nfdata_dma_addr;
|
|
static dma_addr_t nfinfo_dma_addr;
|
|
spinlock_t amlnf_lock;
|
|
wait_queue_head_t amlnf_wq;
|
|
#endif
|
|
|
|
struct list_head nphy_dev_list;
|
|
struct list_head nf_dev_list;
|
|
|
|
void *aml_nand_malloc(u32 size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
void aml_nand_free(void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
#ifndef AML_NAND_UBOOT
|
|
void *amlnf_dma_malloc(uint32 size, unsigned char flag)
|
|
{
|
|
if (flag == 0) //data
|
|
return dma_alloc_coherent(NULL, size, &nfdata_dma_addr, GFP_KERNEL);
|
|
if (flag == 1) //usr
|
|
return dma_alloc_coherent(NULL, size, &nfinfo_dma_addr, GFP_KERNEL);
|
|
}
|
|
|
|
void amlnf_dma_free(const void *ptr, u32 size, u8 flag)
|
|
{
|
|
if (flag == 0) /* data */
|
|
dma_free_coherent(NULL, size, (void *)ptr, nfdata_dma_addr);
|
|
if (flag == 1) /* usr */
|
|
dma_free_coherent(NULL, size, (void *)ptr, nfinfo_dma_addr);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* under os.
|
|
*/
|
|
#ifndef AML_NAND_UBOOT
|
|
int amlphy_prepare(u32 flag)
|
|
{
|
|
spin_lock_init(&amlnf_lock);
|
|
init_waitqueue_head(&amlnf_wq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int phydev_suspend(struct amlnand_phydev *phydev)
|
|
{
|
|
struct amlnand_chip *aml_chip = (struct amlnand_chip *)phydev->priv;
|
|
#ifdef AML_NAND_RB_IRQ
|
|
u32 flags;
|
|
#endif
|
|
|
|
if (!strncmp((char *)phydev->name,
|
|
NAND_BOOT_NAME,
|
|
strlen((const char *)NAND_BOOT_NAME)))
|
|
return 0;
|
|
aml_nand_dbg("phydev_suspend: entered!");
|
|
#ifdef AML_NAND_RB_IRQ
|
|
spin_lock_irqsave(&amlnf_lock, flags);
|
|
#else
|
|
spin_lock(&amlnf_lock);
|
|
#endif
|
|
set_chip_state(aml_chip, CHIP_PM_SUSPENDED);
|
|
#ifdef AML_NAND_RB_IRQ
|
|
spin_unlock_irqrestore(&amlnf_lock, flags);
|
|
#else
|
|
spin_unlock(&amlnf_lock);
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
|
|
void phydev_resume(struct amlnand_phydev *phydev)
|
|
{
|
|
amlchip_resume(phydev);
|
|
return;
|
|
}
|
|
|
|
int nand_idleflag = 0;
|
|
#define NAND_CTRL_NONE_RB (1<<1)
|
|
void nand_get_chip(void *chip)
|
|
{
|
|
struct amlnand_chip *aml_chip = (struct amlnand_chip *)chip;
|
|
struct hw_controller *controller = &(aml_chip->controller);
|
|
int retry = 0, ret;
|
|
|
|
while (1) {
|
|
/* mutex_lock(&spi_nand_mutex); */
|
|
nand_idleflag = 1;
|
|
if ((controller->option & NAND_CTRL_NONE_RB) == 0)
|
|
ret = pinctrl_select_state(aml_chip->nand_pinctrl ,
|
|
aml_chip->nand_rbstate);
|
|
else
|
|
ret = pinctrl_select_state(aml_chip->nand_pinctrl ,
|
|
aml_chip->nand_norbstate);
|
|
if (ret < 0)
|
|
aml_nand_msg("%s:%d %s can't get pinctrl",
|
|
__func__,
|
|
__LINE__,
|
|
dev_name(&aml_chip->device));
|
|
else
|
|
break;
|
|
|
|
if (retry++ > 10)
|
|
aml_nand_msg("get pin fail over 10 times retry=%d",
|
|
retry);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void nand_release_chip(void *chip)
|
|
{
|
|
struct amlnand_chip *aml_chip = (struct amlnand_chip *)chip;
|
|
struct hw_controller *controller = &(aml_chip->controller);
|
|
int ret;
|
|
|
|
if (nand_idleflag) {
|
|
/* enter standby state. */
|
|
controller->enter_standby(controller);
|
|
ret = pinctrl_select_state(aml_chip->nand_pinctrl,
|
|
aml_chip->nand_idlestate);
|
|
if (ret < 0)
|
|
aml_nand_msg("select idle state error");
|
|
nand_idleflag = 0;
|
|
/* mutex_unlock(&spi_nand_mutex); */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* amlnand_get_device - [GENERIC] Get chip for selected access
|
|
*
|
|
* Get the device and lock it for exclusive access
|
|
*/
|
|
int amlnand_get_device(struct amlnand_chip *aml_chip,
|
|
enum chip_state_t new_state)
|
|
{
|
|
#ifdef AML_NAND_RB_IRQ
|
|
u32 flags;
|
|
#endif
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
retry:
|
|
#ifdef AML_NAND_RB_IRQ
|
|
spin_lock_irqsave(&amlnf_lock, flags);
|
|
#else
|
|
spin_lock(&amlnf_lock);
|
|
#endif
|
|
if (get_chip_state(aml_chip) == CHIP_READY) {
|
|
set_chip_state(aml_chip, new_state);
|
|
#ifdef AML_NAND_RB_IRQ
|
|
spin_unlock_irqrestore(&amlnf_lock, flags);
|
|
#else
|
|
spin_unlock(&amlnf_lock);
|
|
#endif
|
|
/* set nand pinmux here */
|
|
nand_get_chip(aml_chip);
|
|
return 0;
|
|
}
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
add_wait_queue(&amlnf_wq, &wait);
|
|
#ifdef AML_NAND_IRQ_MODE
|
|
spin_unlock_irqrestore(&amlnf_lock, flags);
|
|
#else
|
|
spin_unlock(&amlnf_lock);
|
|
#endif
|
|
schedule();
|
|
remove_wait_queue(&amlnf_wq, &wait);
|
|
|
|
goto retry;
|
|
}
|
|
|
|
/**
|
|
* nand_release_device - [GENERIC] release chip
|
|
* @aml_chip: nand chip structure
|
|
*
|
|
* Deselect, release chip lock and wake up anyone waiting on the device
|
|
*/
|
|
void amlnand_release_device(struct amlnand_chip *aml_chip)
|
|
{
|
|
#ifdef AML_NAND_RB_IRQ
|
|
u32 flags;
|
|
#endif
|
|
/* Release the controller and the chip */
|
|
#ifdef AML_NAND_RB_IRQ
|
|
spin_lock_irqsave(&amlnf_lock, flags);
|
|
#else
|
|
spin_lock(&amlnf_lock);
|
|
#endif
|
|
set_chip_state(aml_chip, CHIP_READY);
|
|
wake_up(&amlnf_wq);
|
|
#ifdef AML_NAND_RB_IRQ
|
|
spin_unlock_irqrestore(&amlnf_lock, flags);
|
|
#else
|
|
spin_unlock(&amlnf_lock);
|
|
#endif
|
|
/* clear nand pinmux here */
|
|
nand_release_chip(aml_chip);
|
|
}
|
|
|
|
#else /* AML_NAND_UBOOT, uboot ways below */
|
|
|
|
#ifndef P_PAD_DS_REG0A
|
|
#define P_PAD_DS_REG0A (volatile uint32_t *)(0xff634400 + (0x0d0 << 2))
|
|
#endif
|
|
|
|
void nand_get_chip(void *chip)
|
|
{
|
|
/* fixme, */
|
|
cpu_id_t cpu_id = get_cpu_id();
|
|
|
|
/* pull up enable */
|
|
aml_nand_dbg("PAD_PULL_UP_EN_REG2 0x%x, PAD_PULL_UP_REG2 0x%x, PERIPHS_PIN_MUX_4 0x%x", P_PAD_PULL_UP_EN_REG2, P_PAD_PULL_UP_REG2, P_PERIPHS_PIN_MUX_4);
|
|
|
|
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_G12A) {
|
|
AMLNF_SET_REG_MASK(P_PAD_PULL_UP_EN_REG4, 0x1FFF);
|
|
AMLNF_SET_REG_MASK(P_PAD_PULL_UP_REG4, 0x1F00);
|
|
AMLNF_WRITE_REG(P_PERIPHS_PIN_MUX_0, 0x11111111);
|
|
AMLNF_WRITE_REG(P_PERIPHS_PIN_MUX_1, 0x22122222);
|
|
if(cpu_id.family_id == MESON_CPU_MAJOR_ID_G12A) {
|
|
if (cpu_id.chip_rev == 0xA) {
|
|
writel(0x55555555, P_PAD_DS_REG0A);
|
|
} else if (cpu_id.chip_rev >= 0xB) {
|
|
writel(0xFFFFFFFF, P_PAD_DS_REG0A);
|
|
}
|
|
} else
|
|
writel(0x55555555, P_PAD_DS_REG0A);
|
|
} else {
|
|
AMLNF_SET_REG_MASK(P_PAD_PULL_UP_EN_REG2, 0x87ff);
|
|
/* pull direction, dqs pull down */
|
|
AMLNF_SET_REG_MASK(P_PAD_PULL_UP_REG2, 0x8700);
|
|
/* switch pinmux */
|
|
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXL) {
|
|
AMLNF_CLEAR_REG_MASK(P_PERIPHS_PIN_MUX_7,
|
|
((0x7 << 28) | (0x1FF << 15) | (0xF << 10)));
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_7, ((0x1<<31) | 0xff));
|
|
} else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_GXBB) {
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_4, ((0x1<<30) | (0x3ff<<20)));
|
|
AMLNF_CLEAR_REG_MASK(P_PERIPHS_PIN_MUX_0, (0x1 << 19));
|
|
AMLNF_CLEAR_REG_MASK(P_PERIPHS_PIN_MUX_4, (0x3 << 18));
|
|
AMLNF_CLEAR_REG_MASK(P_PERIPHS_PIN_MUX_5, (0xF));
|
|
}
|
|
aml_nand_dbg("PAD_PULL_UP_EN_REG2 0x%x, PAD_PULL_UP_REG2 0x%x, PERIPHS_PIN_MUX_4 0x%x", AMLNF_READ_REG(P_PAD_PULL_UP_EN_REG2), AMLNF_READ_REG(P_PAD_PULL_UP_REG2), AMLNF_READ_REG(P_PERIPHS_PIN_MUX_4));
|
|
}
|
|
return ;
|
|
}
|
|
|
|
void nand_release_chip(void *chip)
|
|
{
|
|
struct amlnand_chip *aml_chip = (struct amlnand_chip *)chip;
|
|
struct hw_controller * controller;
|
|
cpu_id_t cpu_id = get_cpu_id();
|
|
|
|
controller = &aml_chip->controller;
|
|
NFC_SEND_CMD_STANDBY(controller, 5);
|
|
/* do not release cs0 & cs1 */
|
|
//fixme,
|
|
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXL) {
|
|
//AMLNF_CLEAR_REG_MASK(P_PERIPHS_PIN_MUX_7, ((0x1<<30) | (0x3f << 30)));
|
|
} else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_GXBB) {
|
|
//AMLNF_CLEAR_REG_MASK(P_PERIPHS_PIN_MUX_2, ((0x33f<<20) | (0x1<< 30)));
|
|
}
|
|
return;
|
|
}
|
|
|
|
int amlnand_get_device(struct amlnand_chip *aml_chip, enum chip_state_t new_state)
|
|
{
|
|
nand_get_chip(aml_chip);
|
|
set_chip_state(aml_chip, new_state);
|
|
return 0;
|
|
}
|
|
|
|
void amlnand_release_device(struct amlnand_chip *aml_chip)
|
|
{
|
|
set_chip_state(aml_chip, CHIP_READY);
|
|
//clear nand pinmux here
|
|
nand_release_chip(aml_chip);
|
|
}
|
|
#endif
|
|
|
|
|
|
void pinmux_select_chip(unsigned ce_enable, unsigned rb_enable, unsigned flag)
|
|
{
|
|
#ifdef AML_NAND_UBOOT
|
|
cpu_id_t cpu_id = get_cpu_id();
|
|
|
|
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_G12A) {
|
|
if (!((ce_enable >> 10) & 1))
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_1, (2 << 12));
|
|
} else {
|
|
if (!((ce_enable >> 10) & 1))
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_4, (1 << 26));
|
|
if (!((ce_enable >> 10) & 2))
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_4, (1 << 27));
|
|
if (!((ce_enable >> 10) & 4))
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_4, (1 << 28));
|
|
if (!((ce_enable >> 10) & 8))
|
|
AMLNF_SET_REG_MASK(P_PERIPHS_PIN_MUX_4, (1 << 29));
|
|
}
|
|
#endif /* */
|
|
|
|
}
|
|
|
|
void set_nand_core_clk(struct hw_controller *controller, int clk_freq)
|
|
{
|
|
cpu_id_t cpu_id = get_cpu_id();
|
|
if ((cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXBB)) {
|
|
/* basic test code for gxb using 24Mhz, fixme. */
|
|
//amlnf_write_reg32(controller->nand_clk_reg, 0x81000201); //24Mhz/1
|
|
if (clk_freq == 200) {
|
|
/* 1000Mhz/5 = 200Mhz */
|
|
amlnf_write_reg32(controller->nand_clk_reg, 0x81000245);
|
|
}
|
|
else if (clk_freq == 250) {
|
|
/* 1000Mhz/4 = 250Mhz */
|
|
amlnf_write_reg32(controller->nand_clk_reg, 0x81000244);
|
|
} else {
|
|
/* 1000Mhz/5 = 200Mhz */
|
|
amlnf_write_reg32(controller->nand_clk_reg, 0x81000245);
|
|
printk("%s() %d, using default clock setting!\n", __func__, __LINE__);
|
|
}
|
|
//printk("clk_reg 0x%x\n", AMLNF_READ_REG(controller->nand_clk_reg));
|
|
return;
|
|
} else {
|
|
printk("cpu type can not support!\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void get_sys_clk_rate(struct hw_controller *controller, int *rate)
|
|
{
|
|
u32 cpu_type;
|
|
#ifndef AML_NAND_UBOOT
|
|
struct clk *sys_clk;
|
|
#endif
|
|
|
|
cpu_type = get_cpu_type();
|
|
if (cpu_type >= MESON_CPU_MAJOR_ID_M8) {
|
|
/* 200-250Mhz */
|
|
set_nand_core_clk(controller, *rate);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
set nand info into page0_buf
|
|
*/
|
|
void nand_boot_info_prepare(struct amlnand_phydev *phydev,
|
|
u8 *page0_buf)
|
|
{
|
|
struct amlnand_chip *aml_chip = (struct amlnand_chip *)phydev->priv;
|
|
struct nand_flash *flash = &(aml_chip->flash);
|
|
struct phydev_ops *devops = &(phydev->ops);
|
|
struct hw_controller *controller = &(aml_chip->controller);
|
|
struct en_slc_info *slc_info = NULL;
|
|
int i, nand_read_info;
|
|
u32 en_slc, configure_data;
|
|
u32 boot_num = 1, each_boot_pages;
|
|
u32 valid_pages = BOOT_COPY_NUM * BOOT_PAGES_PER_COPY;
|
|
|
|
nand_page0_t * p_nand_page0 = NULL;
|
|
ext_info_t * p_ext_info = NULL;
|
|
nand_setup_t * p_nand_setup = NULL;
|
|
u32 pages_per_blk_shift;
|
|
|
|
slc_info = &(controller->slc_info);
|
|
|
|
p_nand_page0 = (nand_page0_t *) page0_buf;
|
|
p_nand_setup = &p_nand_page0->nand_setup;
|
|
p_ext_info = &p_nand_page0->ext_info;
|
|
|
|
|
|
configure_data = NFC_CMD_N2M(controller->ran_mode,
|
|
controller->bch_mode, 0, (controller->ecc_unit >> 3),
|
|
controller->ecc_steps);
|
|
/* hynix 2x and lower... */
|
|
if (((flash->new_type < 10) && (flash->new_type))
|
|
|| (slc_info->micron_l0l3_mode == 1))
|
|
en_slc = 1;
|
|
else if (flash->new_type == SANDISK_19NM)
|
|
en_slc = 2;
|
|
else
|
|
en_slc = 0;
|
|
|
|
//memset(page0_buf, 0x0, flash->pagesize);
|
|
memset(p_nand_page0, 0x0, sizeof(nand_page0_t));
|
|
p_nand_setup->cfg.d32 = (configure_data|(1<<23) | (1<<22) | (2<<20) | (1<<19));
|
|
printk("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);
|
|
if (en_slc) {
|
|
p_nand_setup->cfg.b.page_list = 1;
|
|
if (en_slc == 1) {
|
|
memcpy(p_nand_page0->page_list,
|
|
(u8 *)(&slc_info->pagelist[1]),
|
|
NAND_PAGELIST_CNT);
|
|
} else if (en_slc == 2) {
|
|
p_nand_setup->cfg.b.a2 = 1;
|
|
for (i = 1; i < NAND_PAGELIST_CNT; i++)
|
|
p_nand_page0->page_list[i-1] = i<<1;
|
|
}
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
aml_nand_msg("valid_pages = %d en_slc = %d devops->len = %llx",
|
|
valid_pages,
|
|
en_slc, devops->len);
|
|
valid_pages = (en_slc)?(valid_pages>>1):valid_pages;
|
|
for (i = 1;
|
|
i < ((valid_pages*flash->pagesize)/devops->len + 1); i++) {
|
|
if (((valid_pages*flash->pagesize)/(2*i) >= devops->len)
|
|
&& (boot_num < 4))
|
|
boot_num <<= 1;
|
|
else
|
|
break;
|
|
}
|
|
each_boot_pages = valid_pages/boot_num;
|
|
each_boot_pages = (en_slc)?(each_boot_pages<<1):each_boot_pages;
|
|
|
|
p_ext_info->read_info = nand_read_info;
|
|
p_ext_info->new_type = aml_chip->flash.new_type;
|
|
p_ext_info->page_per_blk = flash->blocksize / flash->pagesize;
|
|
p_ext_info->ce_mask = aml_chip->ce_bit_mask;
|
|
p_ext_info->xlc = 2;
|
|
p_ext_info->boot_num = boot_num;
|
|
p_ext_info->each_boot_pages = each_boot_pages;
|
|
#if (SUPPORT_DDR_PARAMETER)
|
|
pages_per_blk_shift =
|
|
(controller->block_shift - controller->page_shift);
|
|
p_nand_page0->fip_info.fip_start = 0;
|
|
p_nand_page0->fip_info.mode = 0;
|
|
p_nand_page0->fip_info.version = 0;
|
|
p_nand_page0->ddrp_start_page =
|
|
(aml_chip->nand_ddr_para.valid_blk_addr << pages_per_blk_shift) + \
|
|
aml_chip->nand_ddr_para.valid_page_addr;
|
|
printk("ddrp blk = 0x%x ddr_page = 0x%x\n",
|
|
aml_chip->nand_ddr_para.valid_blk_addr,
|
|
aml_chip->nand_ddr_para.valid_page_addr);
|
|
#endif
|
|
if (slc_info->micron_l0l3_mode == 1)
|
|
p_ext_info->new_type |= (1<<31);/* mircon l0l3 type mode*/
|
|
printk("new_type = 0x%x\n", p_ext_info->new_type);
|
|
printk("page_per_blk = 0x%x\n", p_ext_info->page_per_blk);
|
|
aml_nand_msg("boot_num = %d each_boot_pages = %d", boot_num,
|
|
each_boot_pages);
|
|
}
|
|
|
|
void uboot_set_ran_mode(struct amlnand_phydev *phydev)
|
|
{
|
|
struct amlnand_chip *aml_chip = (struct amlnand_chip *)phydev->priv;
|
|
struct hw_controller *controller = &(aml_chip->controller);
|
|
|
|
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_M8)
|
|
controller->ran_mode = 1;
|
|
else
|
|
controller->ran_mode = 0;
|
|
}
|
|
|
|
int aml_sys_info_init(struct amlnand_chip *aml_chip)
|
|
{
|
|
#if (AML_CFG_KEY_RSV_EN)
|
|
struct nand_arg_info *nand_key = &aml_chip->nand_key;
|
|
#endif
|
|
#ifdef CONFIG_SECURE_NAND
|
|
struct nand_arg_info *nand_secure = &aml_chip->nand_secure;
|
|
#endif
|
|
#if (AML_CFG_DTB_RSV_EN)
|
|
struct nand_arg_info *amlnf_dtb = &aml_chip->amlnf_dtb;
|
|
#endif
|
|
#if (SUPPORT_DDR_PARAMETER)
|
|
struct nand_arg_info *amlnf_ddr_para = &aml_chip->nand_ddr_para;
|
|
#endif
|
|
struct nand_arg_info *uboot_env = &aml_chip->uboot_env;
|
|
struct nand_flash *flash = &aml_chip->flash;
|
|
u8 *buf = NULL;
|
|
u32 buf_size = 0;
|
|
int ret = 0;
|
|
|
|
buf_size = 0x40000; /*rsv item max size is 256KB*/
|
|
buf = aml_nand_malloc(buf_size + flash->pagesize);
|
|
if (!buf) {
|
|
aml_nand_msg("aml_sys_info_init : malloc failed");
|
|
return -1;
|
|
}
|
|
memset(buf, 0x0, buf_size);
|
|
NAND_LINE
|
|
#if (AML_CFG_KEY_RSV_EN)
|
|
if (nand_key->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = aml_key_init(aml_chip);
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand key init failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if (SUPPORT_DDR_PARAMETER)
|
|
if (amlnf_ddr_para->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = aml_ddr_parameter_init(aml_chip);
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand ddr parameter init failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_SECURE_NAND
|
|
if (nand_secure->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = aml_secure_init(aml_chip);
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand secure init failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
#if (AML_CFG_DTB_RSV_EN)
|
|
if (amlnf_dtb->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = amlnf_dtb_init(aml_chip);
|
|
if (ret < 0) {
|
|
aml_nand_msg("amlnf dtb init failed");
|
|
/* fixme, should go on! */
|
|
//goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
NAND_LINE
|
|
printk("boot_device_flag %d\n", boot_device_flag);
|
|
if ((uboot_env->arg_valid == 0) && (boot_device_flag == 1)) {
|
|
NAND_LINE
|
|
ret = aml_ubootenv_init(aml_chip);
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand uboot env init failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
|
|
#if (AML_CFG_KEY_RSV_EN)
|
|
if (nand_key->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = amlnand_save_info_by_name(aml_chip,
|
|
(u8 *)(&(aml_chip->nand_key)),
|
|
buf,
|
|
(u8 *)KEY_INFO_HEAD_MAGIC,
|
|
aml_chip->keysize);
|
|
NAND_LINE
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand save default key failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if (SUPPORT_DDR_PARAMETER)
|
|
if (amlnf_ddr_para->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = amlnand_save_info_by_name(aml_chip,
|
|
(u8 *)(&(aml_chip->nand_ddr_para)),
|
|
buf,
|
|
(u8 *)DDR_PARAMETER_HEAD_MAGIC,
|
|
aml_chip->ddrsize);
|
|
NAND_LINE
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand save default ddr parameter failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_SECURE_NAND
|
|
/*save a empty value! */
|
|
if (nand_secure->arg_valid == 0) {
|
|
NAND_LINE
|
|
ret = amlnand_save_info_by_name(aml_chip,
|
|
(u8 *)&(aml_chip->nand_secure),
|
|
buf,
|
|
(u8 *)SECURE_INFO_HEAD_MAGIC,
|
|
CONFIG_SECURE_SIZE);
|
|
if (ret < 0) {
|
|
aml_nand_msg("nand save default secure_ptr failed");
|
|
goto exit_error;
|
|
}
|
|
}
|
|
#endif
|
|
#if (AML_CFG_DTB_RSV_EN)
|
|
/* fixme, no need to save a empty dtb. */
|
|
#endif
|
|
NAND_LINE
|
|
exit_error:
|
|
aml_nand_free(buf);
|
|
buf = NULL;
|
|
return ret;
|
|
}
|
|
|
|
#ifdef AML_NAND_UBOOT
|
|
/*fixme, */
|
|
extern int info_disprotect;
|
|
|
|
void amlnf_disprotect(char * name)
|
|
{
|
|
//struct amlnand_chip *aml_chip = aml_nand_chip;
|
|
|
|
/* #ifdef CONFIG_SECURITYKEY */
|
|
if (strcmp((const char *)name, "key") == 0) {
|
|
aml_nand_msg("disprotect key");
|
|
info_disprotect |= DISPROTECT_KEY;
|
|
aml_nand_chip->protect |= DISPROTECT_KEY;
|
|
}
|
|
/*#endif */
|
|
|
|
#ifdef CONFIG_SECURE_NAND
|
|
if (strcmp((const char *)name, "secure") == 0) {
|
|
aml_nand_msg("disprotect secure");
|
|
info_disprotect |= DISPROTECT_SECURE;
|
|
aml_nand_chip->protect |= DISPROTECT_SECURE;
|
|
}
|
|
#endif
|
|
|
|
if (strcmp((const char *)name, "fbbt") == 0) {
|
|
aml_nand_msg("disprotect fbbt");
|
|
info_disprotect |= DISPROTECT_FBBT;
|
|
aml_nand_chip->protect |= DISPROTECT_FBBT;
|
|
}
|
|
if (strcmp((const char *)name, "hynix") == 0) {
|
|
aml_nand_msg("disprotect hynix");
|
|
info_disprotect |= DISPROTECT_HYNIX;
|
|
aml_nand_chip->protect |= DISPROTECT_HYNIX;
|
|
}
|
|
if (strcmp((const char *)name, "dbg") == 0) {
|
|
aml_nand_msg("disprotect dbg");
|
|
info_disprotect |= DISPROTECT_DBG;
|
|
aml_nand_chip->protect |= DISPROTECT_DBG;
|
|
}
|
|
aml_nand_msg("disprotect 0x%08x", info_disprotect);
|
|
return ;
|
|
}
|
|
|
|
#endif
|