Files

389 lines
10 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <amlogic/page_info.h>
#include <amlogic/storage.h>
#include <nand.h>
struct boot_info *page_info;
#ifdef CONFIG_AML_SPI_NFC
extern unsigned char infopage_force_hostecc;
extern unsigned char disable_host_ecc;
#endif
extern struct mtd_info *mtd_store_get(int dev);
unsigned char page_info_get_data_lanes_mode(void)
{
return page_info->dev_cfg0.bus_width & 0x0f;
}
unsigned char page_info_get_cmd_lanes_mode(void)
{
return page_info->dev_cfg1.ca_lanes & 0x0f;
}
unsigned char page_info_get_addr_lanes_mode(void)
{
return (page_info->dev_cfg1.ca_lanes >> 4) & 0x0f;
}
unsigned char page_info_get_frequency_index(void)
{
return page_info->host_cfg.frequency_index;
}
unsigned char page_info_get_adj_index(void)
{
return page_info->host_cfg.mode_rx_adj & 0x3f;
}
unsigned char page_info_get_work_mode(void)
{
return (page_info->host_cfg.mode_rx_adj >> 6) & 0x3;
}
unsigned char page_info_get_line_delay1(void)
{
return page_info->host_cfg.lines_delay[0];
}
unsigned char page_info_get_line_delay2(void)
{
return page_info->host_cfg.lines_delay[1];
}
unsigned char page_info_get_core_div(void)
{
return page_info->host_cfg.core_div;
}
unsigned char page_info_get_bus_cycle(void)
{
return page_info->host_cfg.bus_cycle;
}
unsigned char page_info_get_device_ecc_disable(void)
{
return page_info->host_cfg.device_ecc_disable & 0x01;
}
unsigned int page_info_get_n2m_command(void)
{
return page_info->host_cfg.n2m_cmd;
}
unsigned int page_info_get_page_size(void)
{
return page_info->dev_cfg0.page_size;
}
unsigned char page_info_get_planes(void)
{
return page_info->dev_cfg0.planes_per_lun & 0x0f;
}
unsigned char page_info_get_plane_shift(void)
{
return (page_info->dev_cfg0.planes_per_lun >> 4) & 0x0f;
}
unsigned char page_info_get_cache_plane_shift(void)
{
return (page_info->dev_cfg0.bus_width >> 4) & 0x0f;
}
unsigned char page_info_get_cs_deselect_time(void)
{
return page_info->dev_cfg1.cs_deselect_time;
}
unsigned char page_info_get_dummy_cycles(void)
{
return page_info->dev_cfg1.dummy_cycles;
}
unsigned int page_info_get_block_size(void)
{
return page_info->dev_cfg1.block_size;
}
unsigned short *page_info_get_bbt(void)
{
return &page_info->dev_cfg1.bbt[0];
}
unsigned char page_info_get_enable_bbt(void)
{
return page_info->dev_cfg1.enable_bbt;
}
unsigned char page_info_get_high_speed_mode(void)
{
return page_info->dev_cfg1.high_speed_mode;
}
unsigned char page_info_get_layout_method(void)
{
return page_info->boot_layout.layout_method;
}
unsigned int page_info_get_boot_size(void)
{
return page_info->boot_layout.boot_size;
}
unsigned int page_info_get_pages_in_block(void)
{
unsigned int block_size, page_size;
static unsigned int pages_in_block;
if (pages_in_block)
return pages_in_block;
block_size = page_info_get_block_size();
page_size = page_info_get_page_size();
pages_in_block = block_size / page_size;
return pages_in_block;
}
unsigned int page_info_get_pages_in_boot(void)
{
unsigned int page_size, boot_size;
page_size = page_info_get_page_size();
boot_size = page_info_get_boot_size();
return boot_size / page_size;
}
void page_info_initialize(unsigned int default_n2m,
unsigned char bus_width, unsigned char ca)
{
memset((unsigned char *)page_info,
0, sizeof(struct boot_info));
page_info->dev_cfg0.page_size = sizeof(struct boot_info);
page_info->dev_cfg0.planes_per_lun = 0;
page_info->dev_cfg0.bus_width = bus_width;
page_info->host_cfg.frequency_index = 0xFF;
page_info->host_cfg.n2m_cmd = default_n2m;
page_info->dev_cfg1.ca_lanes = ca;
page_info->dev_cfg1.cs_deselect_time = 0xFF;
page_info->dev_cfg1.dummy_cycles = 0xFF;
}
int page_info_version_init(unsigned char boot_layout)
{
cpu_id_t cpu_id = get_cpu_id();
switch (cpu_id.family_id) {
case MESON_CPU_MAJOR_ID_A4:
case MESON_CPU_MAJOR_ID_S1A:
page_info->version = PAGE_INFO_V3;
break;
case MESON_CPU_MAJOR_ID_C3:
page_info->version = PAGE_INFO_V2;
break;
case MESON_CPU_MAJOR_ID_A1:
case MESON_CPU_MAJOR_ID_C1:
case MESON_CPU_MAJOR_ID_C2:
case MESON_CPU_MAJOR_ID_S4:
case MESON_CPU_MAJOR_ID_S4D:
case MESON_CPU_MAJOR_ID_S5:
case MESON_CPU_MAJOR_ID_SC2:
page_info->version = PAGE_INFO_V1;
break;
default:
page_info->version = PAGE_INFO_V3;
break;
}
page_info->version |= (boot_layout << 4);
return page_info->version & 0x0F;
}
static void calc_checksum(struct boot_info *boot_info)
{
u8 *buf = (u8 *)boot_info;
u32 i, checksum = 0;
boot_info->checksum = 0;
for (i = 0; i < sizeof(struct boot_info); i++)
checksum += buf[i];
boot_info->checksum = checksum;
printf("bootinfo checksum : 0x%x\n", boot_info->checksum);
}
void page_info_init_from_mtd_and_dts(struct mtd_info *mtd,
struct udevice *udev)
{
unsigned char ecc_steps;
enum PAGE_INFO_V page_info_ver;
u32 boot_layout;
#ifdef CONFIG_MTD_SPI_NAND
enum boot_type_e medium_type = store_get_type();
struct nand_device *dev = mtd_to_nanddev(mtd);
if (medium_type == BOOT_SNAND) {
struct dm_spi_slave_plat *plat;
#ifdef CONFIG_DDR_PARAMETER_SUPPORT
struct spinand_device *spinand = mtd_to_spinand(mtd);
unsigned int pages_shift, ddr_param_page;
#endif
plat = dev_get_parent_plat(udev);
page_info->dev_cfg0.bus_width &= ~0x03;
if (plat->mode & SPI_RX_OCTAL)
page_info->dev_cfg0.bus_width |= 3;
else if (plat->mode & SPI_RX_QUAD)
page_info->dev_cfg0.bus_width |= 2;
else if (plat->mode & SPI_RX_DUAL)
page_info->dev_cfg0.bus_width |= 1;
NFC_Print("bus_width", page_info->dev_cfg0.bus_width);
page_info->dev_cfg0.planes_per_lun = dev->memorg.planes_per_lun;
if (page_info->dev_cfg0.planes_per_lun > 1) {
page_info->dev_cfg0.planes_per_lun |= 6 << 4;
page_info->dev_cfg0.bus_width =
(mtd->writesize_shift + 1) << 4;
}
}
#endif
#ifdef BOARD_BOOT_LAYOUT_DISCRETE_BL2
boot_layout = BOOT_DISCRETE_BL2;
#else
boot_layout = BOOT_DISCRETE_ALL;
#endif
page_info_ver = page_info_version_init(boot_layout);
memcpy(page_info->magic, BOOTINFO_MAGIC, strlen(BOOTINFO_MAGIC));
page_info->dev_cfg0.page_size = mtd->writesize;
ecc_steps = mtd->writesize >> 9;
page_info->host_cfg.n2m_cmd = (DEFAULT_ECC_MODE & (~0x3F)) | ecc_steps;
#ifdef CONFIG_MTD_SPI_NAND
if (medium_type == BOOT_SNAND) {
#ifdef CONFIG_AML_SPI_NFC
if (disable_host_ecc)
page_info->host_cfg.n2m_cmd = N2M_RAW | mtd->writesize;
#endif
page_info->host_cfg.frequency_index = 0xFF;
page_info->dev_cfg1.ca_lanes = 0;
page_info->dev_cfg1.cs_deselect_time = 0xFF;
page_info->dev_cfg1.dummy_cycles = 0xFF;
}
#endif
page_info->dev_cfg1.block_size = mtd->erasesize;
#ifdef BOOTINFO_PROGRAMMER_SUPPORT
page_info->dev_cfg1.is_gang_programer = 0;
page_info->dev_cfg1.xor_bbt_start_block |= (1 << 24);
page_info->dev_cfg1.block_num_in_chip = mtd->size / mtd->erasesize;
if (mtd_store_get(1))
page_info->dev_cfg1.block_num_in_chip =
(mtd_store_get(1))->size / mtd->erasesize;
#endif
if (meson_rsv_part_get_bl2_copy_number(mtd) > 2)
page_info->dev_cfg1.enable_bbt = 1;
calc_checksum(page_info);
}
#ifdef __PXP_DEBUG__
static void page_info_dump_info(void)
{
unsigned char planes_per_lun, plane_shift, bus_width, cache_plane_shift;
unsigned char high_speed_mode, cmd_lanes, addr_lanes;
unsigned char enable_bbt;
unsigned int block_size, page_size;
unsigned char frequency_index, mode, rx_adj;
unsigned char device_ecc_disable = 0;
unsigned int n2m_cmd;
planes_per_lun = page_info_get_planes();
plane_shift = page_info_get_plane_shift();
cache_plane_shift = page_info_get_cache_plane_shift();
high_speed_mode = page_info_get_high_speed_mode();
page_size = page_info_get_page_size();
block_size = page_info_get_block_size();
enable_bbt = page_info_get_enable_bbt();
bus_width = page_info_get_data_lanes_mode();
cmd_lanes = page_info_get_cmd_lanes_mode();
addr_lanes = page_info_get_addr_lanes_mode();
frequency_index = page_info_get_frequency_index();
mode = page_info_get_work_mode();
rx_adj = page_info_get_adj_index();
device_ecc_disable = page_info_get_device_ecc_disable();
n2m_cmd = page_info_get_n2m_command();
pr_info("bus_width: 0x%x\n", bus_width);
pr_info("cmd_lanes: 0x%x\n", cmd_lanes);
pr_info("addr_lanes: 0x%x\n", addr_lanes);
pr_info("page_size: 0x%x\n", page_size);
pr_info("planes_per_lun: 0x%x\n", planes_per_lun);
pr_info("plane_shift: 0x%x\n", plane_shift);
pr_info("cache_plane_shift: 0x%x\n", cache_plane_shift);
pr_info("block_size: 0x%x\n", block_size);
pr_info("high_speed_mode: 0x%x\n", high_speed_mode);
pr_info("enable_bbt: 0x%x\n", enable_bbt);
pr_info("frequency_index: 0x%x\n", frequency_index);
pr_info("mode: 0x%x\n", mode);
pr_info("rx_adj: 0x%x\n", rx_adj);
pr_info("device_ecc_disable: 0x%x\n", device_ecc_disable);
pr_info("n2m_cmd: 0x%x\n", n2m_cmd);
pr_info("is_gang_programer: %d\n", page_info->dev_cfg1.is_gang_programer);
pr_info("xor_bbt_start_block: 0x%x\n", page_info->dev_cfg1.xor_bbt_start_block);
pr_info("block_num_in_chip: %d\n", page_info->dev_cfg1.block_num_in_chip);
pr_info("version: 0x%x\n", page_info->version);
pr_info("layout_method: 0x%x\n", page_info->boot_layout.layout_method);
pr_info("boot size: 0x%x\n", page_info->boot_layout.boot_size);
}
#endif
unsigned char *page_info_post_init(struct mtd_info *mtd, struct udevice *dev)
{
page_info_init_from_mtd_and_dts(mtd, dev);
#ifdef __PXP_DEBUG__
page_info_dump_info();
#endif
return (unsigned char *)page_info;
}
int page_info_pre_init(void)
{
if (!page_info) {
page_info = kzalloc(MAX_BYTES_IN_BOOTINFO, GFP_KERNEL);
if (!page_info)
return -1;
}
return 0;
}
bool page_info_is_page(struct mtd_info *mtd, int page)
{
enum PAGE_INFO_V page_info_ver;
bool is_info_page = 0;
u32 pages_per_copy =
meson_rsv_part_get_bl2_copy_size(mtd) / mtd->writesize;
page_info_ver = page_info->version & 0x0F;
if (page_info_ver == PAGE_INFO_V1)
is_info_page = page % 128 == BL2_SIZE / 2048;
else
is_info_page = (!(page % pages_per_copy));
#ifdef CONFIG_AML_SPI_NFC
if (infopage_force_hostecc) {
if (is_info_page)
disable_host_ecc = 0;
else
disable_host_ecc = 1;
}
#endif
return is_info_page;
}