diff options
Diffstat (limited to 'plat/gxb/storage.c')
-rw-r--r-- | plat/gxb/storage.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/plat/gxb/storage.c b/plat/gxb/storage.c new file mode 100644 index 0000000..2227b70 --- /dev/null +++ b/plat/gxb/storage.c @@ -0,0 +1,497 @@ + +/* + * arch/arm/cpu/armv8/common/firmware/plat/gxb/storage.c + * + * Copyright (C) 2015 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <arch_helpers.h> +#include <stdio.h> +#include <stdint.h> +#include <asm/arch/romboot.h> +#include <string.h> +#include <io.h> +#include <platform_def.h> +#include <storage.h> +#include <asm/arch/io.h> +#include <asm/arch/secure_apb.h> +#include <asm/arch/cpu_sdio.h> +#include <asm/arch/nand.h> +#include <fip.h> +#include <asm/arch/watchdog.h> + +void dump_ddr_data(void) +{ +#ifdef CONFIG_SPL_DDR_DUMP + if (CONFIG_SPL_DDR_DUMP_FLAG == readl(P_PREG_STICKY_REG0)) { + serial_puts("Dump ddr[0x"); + serial_put_hex(CONFIG_SPL_DDR_DUMP_ADDR, 32); + serial_puts("-0x"); + serial_put_hex((CONFIG_SPL_DDR_DUMP_ADDR+CONFIG_SPL_DDR_DUMP_SIZE), 32); + serial_puts("] to "); + serial_puts((CONFIG_SPL_DDR_DUMP_DEV_TYPE==BOOT_DEVICE_SD)?"External":"Internal"); + serial_puts(" device[0x"); + serial_put_hex(CONFIG_SPL_DDR_DUMP_DEV_OFFSET, 32); + serial_puts("-0x"); + serial_put_hex((CONFIG_SPL_DDR_DUMP_DEV_OFFSET+CONFIG_SPL_DDR_DUMP_SIZE), 32); + serial_puts("]\n\n"); + + writel(0, P_PREG_STICKY_REG0); + watchdog_disable(); + sdio_write_data(CONFIG_SPL_DDR_DUMP_DEV_TYPE, CONFIG_SPL_DDR_DUMP_ADDR, \ + CONFIG_SPL_DDR_DUMP_DEV_OFFSET, CONFIG_SPL_DDR_DUMP_SIZE); + reset_system(); + } +#endif + return; +} + +uint64_t storage_init(void) +{ + uint64_t boot_device = 0; + boot_device = get_boot_device(); + switch (boot_device) { +#if defined(CONFIG_AML_NAND) + case BOOT_DEVICE_NAND: + serial_puts( "NAND init\n"); + nfio_init(); + break; +#endif //CONFIG_AML_NAND + default: + //serial_puts("do nothing!\n"); + break; + } + return 0; +} +uint64_t storage_load(uint64_t src, uint64_t des, uint64_t size, const char * image_name) +{ + char * device_name = "UNKNOWN"; + uint64_t boot_device = 0; + + boot_device = get_boot_device(); + //boot_device = BOOT_DEVICE_SPI; + switch (boot_device) { + case BOOT_DEVICE_RESERVED: + device_name = "Rsv"; + break; + case BOOT_DEVICE_EMMC: + device_name = "eMMC"; + break; +#if defined(CONFIG_AML_NAND) + case BOOT_DEVICE_NAND: + device_name = "NAND"; + break; +#endif //CONFIG_AML_NAND + case BOOT_DEVICE_SPI: + device_name = "SPI"; + break; + case BOOT_DEVICE_SD: + device_name = "SD"; + src += 512; //sd boot must add 512 offset + break; + case BOOT_DEVICE_USB: + case BOOT_DEVICE_USB_FORCEMODE: + device_name = "USB"; + break; + default: + break; + } + //printf("Load %s from %s, src: 0x%x, dst: 0x%x, size: 0x%x\n", + // image_name, device_name, src, des, size); + serial_puts("Load "); + serial_puts(image_name); + serial_puts(" from "); + serial_puts(device_name); + serial_puts(", src: 0x"); + serial_put_hex(src, 32); + serial_puts(", des: 0x"); + serial_put_hex(des, 32); + serial_puts(", size: 0x"); + serial_put_hex(size, 32); + serial_puts("\n"); + switch (boot_device) { + case BOOT_DEVICE_RESERVED: + break; + case BOOT_DEVICE_EMMC: + sdio_read_data(boot_device,src, des, size); + break; +#if defined(CONFIG_AML_NAND) + case BOOT_DEVICE_NAND: + nf_read(boot_device, src, des, size); + break; +#endif //CONFIG_AML_NAND + case BOOT_DEVICE_SPI: + spi_read(src, des, size); + break; + case BOOT_DEVICE_SD: + sdio_read_data(boot_device, src, des, size); + break; + case BOOT_DEVICE_USB: + case BOOT_DEVICE_USB_FORCEMODE: + usb_boot(src, des, size); + break; + default: + break; + } +#ifdef BL2_ENABLE_MMU + inv_dcache_range(des, size); +#endif + return 0; +} + +uint64_t spi_read(uint64_t src, uint64_t des, uint64_t size) +{ + /*spi pin mux*/ + *P_PAD_PULL_UP_EN_REG2 = 0xffff87ff; + *P_PAD_PULL_UP_REG2 = 0xffff8700; + // deselect nand/emmc, select spi. + *P_PERIPHS_PIN_MUX_4 &= ~((1<<31) | (7<<22) | (1<<20)); + *P_PERIPHS_PIN_MUX_5 |= 0xf; + + /*spi init*/ + /* use sys_clock_freq: 0x002ab000 //24:0x002ab313 + * use sys_clock_freq/2: 0x002aa101 + * use sys_clock_freq/4: 0x002aa313 + * use sys_clock_freq/8: 0x002aa737 + * use sys_clock_freq/10: 0x002aa949 + * use sys_clock_freq/16: 0x002aaf7f + */ +#ifndef CONFIG_PXP_EMULATOR + writel(0x2aa949,P_SPI_FLASH_CTRL); +#else + writel(0x002ab000,P_SPI_FLASH_CTRL); +#endif + + /*load data*/ + uint64_t des64, src64; + des64 = des; + src64 = src; + memcpy((void *)des64, (void *)(src64 | (uint64_t)P_SPI_START_ADDR), size); + return 0; +} + +uint64_t sdio_read_blocks(struct sd_emmc_global_regs *sd_emmc_regs, + uint64_t src, uint64_t des, uint64_t size, uint64_t mode) +{ + unsigned ret = 0; + unsigned read_start; + unsigned vstart = 0; + unsigned status_irq = 0; + unsigned response[4]; + struct cmd_cfg *des_cmd_cur = NULL; + struct sd_emmc_desc_info desc[MAX_DESC_NUM]; + struct sd_emmc_desc_info *desc_cur; + struct sd_emmc_start *desc_start = (struct sd_emmc_start*)&vstart; + struct sd_emmc_status *status_irq_reg = (void *)&status_irq; + + memset(desc,0,MAX_DESC_NUM*sizeof(struct sd_emmc_desc_info)); + desc_cur = desc; + + if (mode) + read_start = src>>9; + else + read_start = src; + + des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); + //starting reading...... + des_cmd_cur->cmd_index = 18; //read data command + if (mode) { + des_cmd_cur->block_mode = 1; + des_cmd_cur->length = size; + }else{ + des_cmd_cur->block_mode = 0; + des_cmd_cur->length = size; + } + + des_cmd_cur->data_io = 1; + des_cmd_cur->data_wr = 0; + des_cmd_cur->data_num = 0; + des_cmd_cur->no_resp = 0; + des_cmd_cur->resp_num = 0; + des_cmd_cur->timeout = 7; + des_cmd_cur->owner = 1; + des_cmd_cur->end_of_chain = 1; + + desc_cur->cmd_arg = read_start; + desc_cur->data_addr = des; + desc_cur->data_addr &= ~(1<<0); //DDR + desc_cur->resp_addr = (unsigned long)response; + + desc_start->init = 0; + desc_start->busy = 1; + desc_start->addr = (unsigned long)desc >> 2; + sd_emmc_regs->gstatus = 0x3fff; + //sd_emmc_regs->gstart = vstart; + sd_emmc_regs->gcmd_cfg = desc_cur->cmd_info; + sd_emmc_regs->gcmd_dat = desc_cur->data_addr; + sd_emmc_regs->gcmd_arg = desc_cur->cmd_arg; + + + while (1) { + status_irq = sd_emmc_regs->gstatus; + if (status_irq_reg->end_of_chain) + break; + } + //send stop cmd + desc_cur = &desc[1]; + des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); + des_cmd_cur->cmd_index = 12; + des_cmd_cur->data_io = 0; + des_cmd_cur->no_resp = 0; + des_cmd_cur->r1b = 1; + des_cmd_cur->owner = 1; + des_cmd_cur->end_of_chain = 1; + + desc_start->init = 0; + desc_start->busy = 1; + desc_start->addr = (unsigned long)desc_cur >> 2; + sd_emmc_regs->gstatus = 0x3fff; + //sd_emmc_regs->gstart = vstart; + sd_emmc_regs->gcmd_cfg = desc_cur->cmd_info; + sd_emmc_regs->gcmd_dat = desc_cur->data_addr; + sd_emmc_regs->gcmd_arg = desc_cur->cmd_arg; + + while (1) { + status_irq = sd_emmc_regs->gstatus; + //printf("status_irq=0x%x\n",status_irq); + if (status_irq_reg->end_of_chain) + break; + } + + if (status_irq_reg->rxd_err) + ret |= SD_EMMC_RXD_ERROR; + if (status_irq_reg->txd_err) + ret |= SD_EMMC_TXD_ERROR; + if (status_irq_reg->desc_err) + ret |= SD_EMMC_DESC_ERROR; + if (status_irq_reg->resp_err) + ret |= SD_EMMC_RESP_CRC_ERROR; + if (status_irq_reg->resp_timeout) + ret |= SD_EMMC_RESP_TIMEOUT_ERROR; + if (status_irq_reg->desc_timeout) + ret |= SD_EMMC_DESC_TIMEOUT_ERROR; + if (ret) { + serial_puts("sd/emmc read data error: ret="); + serial_put_dec(ret); + serial_puts("\n"); + } + //else + //serial_puts("read data success!\n"); + return ret; +} + +#ifdef CONFIG_SPL_DDR_DUMP +uint64_t sdio_write_blocks(struct sd_emmc_global_regs *sd_emmc_regs, + uint64_t src, uint64_t des, uint64_t size, uint64_t mode) +{ + unsigned ret = 0; + unsigned write_start; + unsigned vstart = 0; + unsigned status_irq = 0; + unsigned response[4]; + struct cmd_cfg *des_cmd_cur = NULL; + struct sd_emmc_desc_info desc[MAX_DESC_NUM]; + struct sd_emmc_desc_info *desc_cur; + struct sd_emmc_start *desc_start = (struct sd_emmc_start*)&vstart; + struct sd_emmc_status *status_irq_reg = (void *)&status_irq; + + memset(desc,0,MAX_DESC_NUM*sizeof(struct sd_emmc_desc_info)); + desc_cur = desc; + + if (mode) + write_start = des>>9; + else + write_start = des; + + des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); + //starting reading...... + des_cmd_cur->cmd_index = 25; //muti write data command + if (mode) { + des_cmd_cur->block_mode = 1; + des_cmd_cur->length = size; + }else{ + des_cmd_cur->block_mode = 0; + des_cmd_cur->length = size; + } + + des_cmd_cur->data_io = 1; + des_cmd_cur->data_wr = 1; + des_cmd_cur->data_num = 0; + des_cmd_cur->no_resp = 0; + des_cmd_cur->resp_num = 0; + des_cmd_cur->timeout = 7; + des_cmd_cur->owner = 1; + des_cmd_cur->end_of_chain = 1; + + desc_cur->cmd_arg = write_start; + desc_cur->data_addr = src; + desc_cur->data_addr &= ~(1<<0); //DDR + desc_cur->resp_addr = (unsigned long)response; + + desc_start->init = 0; + desc_start->busy = 1; + desc_start->addr = (unsigned long)desc >> 2; + sd_emmc_regs->gstatus = 0x3fff; + //sd_emmc_regs->gstart = vstart; + sd_emmc_regs->gcmd_cfg = desc_cur->cmd_info; + sd_emmc_regs->gcmd_dat = desc_cur->data_addr; + sd_emmc_regs->gcmd_arg = desc_cur->cmd_arg; + + + while (1) { + status_irq = sd_emmc_regs->gstatus; + if (status_irq_reg->end_of_chain) + break; + } + //send stop cmd + desc_cur = &desc[1]; + des_cmd_cur = (struct cmd_cfg *)&(desc_cur->cmd_info); + des_cmd_cur->cmd_index = 12; + des_cmd_cur->data_io = 0; + des_cmd_cur->no_resp = 0; + des_cmd_cur->r1b = 1; + des_cmd_cur->owner = 1; + des_cmd_cur->end_of_chain = 1; + + desc_start->init = 0; + desc_start->busy = 1; + desc_start->addr = (unsigned long)desc_cur >> 2; + sd_emmc_regs->gstatus = 0x3fff; + //sd_emmc_regs->gstart = vstart; + sd_emmc_regs->gcmd_cfg = desc_cur->cmd_info; + sd_emmc_regs->gcmd_dat = desc_cur->data_addr; + sd_emmc_regs->gcmd_arg = desc_cur->cmd_arg; + + while (1) { + status_irq = sd_emmc_regs->gstatus; + //printf("status_irq=0x%x\n",status_irq); + if (status_irq_reg->end_of_chain) + break; + } + + if (status_irq_reg->rxd_err) + ret |= SD_EMMC_RXD_ERROR; + if (status_irq_reg->txd_err) + ret |= SD_EMMC_TXD_ERROR; + if (status_irq_reg->desc_err) + ret |= SD_EMMC_DESC_ERROR; + if (status_irq_reg->resp_err) + ret |= SD_EMMC_RESP_CRC_ERROR; + if (status_irq_reg->resp_timeout) + ret |= SD_EMMC_RESP_TIMEOUT_ERROR; + if (status_irq_reg->desc_timeout) + ret |= SD_EMMC_DESC_TIMEOUT_ERROR; + if (ret) { + serial_puts("sd/emmc write data error: ret="); + serial_put_dec(ret); + serial_puts("\n"); + } + //else + //serial_puts("write data success!\n"); + return ret; +} +#endif // #ifdef CONFIG_SPL_DDR_DUMP + +uint64_t sdio_read_data(uint64_t boot_device, uint64_t src, uint64_t des, uint64_t size) +{ + unsigned mode,blk_cnt,ret; + struct sd_emmc_global_regs *sd_emmc_regs=0; + union sd_emmc_setup *s_setup = (union sd_emmc_setup *)SEC_AO_SEC_GP_CFG1; + + if (boot_device == BOOT_DEVICE_EMMC) + sd_emmc_regs = (struct sd_emmc_global_regs *)SD_EMMC_BASE_C; + else if(boot_device == BOOT_DEVICE_SD) + sd_emmc_regs = (struct sd_emmc_global_regs *)SD_EMMC_BASE_B; + else + serial_puts("sd/emmc boot device error\n"); + + mode = s_setup->b.sdhc | s_setup->b.hcs ? 1 : 0; + +#if 0 + if (mode) + serial_puts("sd/emmc is lba mode\n"); + else + serial_puts("sd/emmc is byte mode\n"); +#endif + + blk_cnt = ((size+511)&(~(511)))>>9; + do { + ret = sdio_read_blocks(sd_emmc_regs,src,des,(blk_cnt>MAX_BLOCK_COUNTS)?MAX_BLOCK_COUNTS:blk_cnt,mode); + if (ret) + return ret; + if (blk_cnt>MAX_BLOCK_COUNTS) { + src += MAX_BLOCK_COUNTS<<9; + des += MAX_BLOCK_COUNTS<<9; + blk_cnt -= MAX_BLOCK_COUNTS; + }else + break; + }while(1); + + return ret; +} + +#ifdef CONFIG_SPL_DDR_DUMP +uint64_t sdio_write_data(uint64_t boot_device, uint64_t src, uint64_t des, uint64_t size) +{ + unsigned mode,blk_cnt,ret; + struct sd_emmc_global_regs *sd_emmc_regs=0; + union sd_emmc_setup *s_setup = (union sd_emmc_setup *)SEC_AO_SEC_GP_CFG1; + + if (boot_device == BOOT_DEVICE_EMMC) + sd_emmc_regs = (struct sd_emmc_global_regs *)SD_EMMC_BASE_C; + else if(boot_device == BOOT_DEVICE_SD) + sd_emmc_regs = (struct sd_emmc_global_regs *)SD_EMMC_BASE_B; + else + serial_puts("sd/emmc boot device error\n"); + + mode = s_setup->b.sdhc | s_setup->b.hcs ? 1 : 0; + +#if 0 + if (mode) + serial_puts("sd/emmc is lba mode\n"); + else + serial_puts("sd/emmc is byte mode\n"); +#endif + + blk_cnt = ((size+511)&(~(511)))>>9; + do { + ret = sdio_write_blocks(sd_emmc_regs,src,des,(blk_cnt>MAX_BLOCK_COUNTS)?MAX_BLOCK_COUNTS:blk_cnt,mode); + if (ret) + return ret; + if (blk_cnt>MAX_BLOCK_COUNTS) { + src += MAX_BLOCK_COUNTS<<9; + des += MAX_BLOCK_COUNTS<<9; + blk_cnt -= MAX_BLOCK_COUNTS; + }else + break; + }while(1); + + return ret; +} +#endif // #ifdef CONFIG_SPL_DDR_DUMP + +uint64_t get_boot_device(void) { + const unsigned forceUsbRegVal = readl(SEC_AO_RTI_STATUS_REG3); + const unsigned forceUsbBootFlag = ( forceUsbRegVal>>12 ) & 0xF; + if ( 2 == forceUsbBootFlag) return BOOT_DEVICE_USB_FORCEMODE; + + return (readl(SEC_AO_SEC_GP_CFG0) & 0xf); +} + +uint64_t get_ddr_size(void) { + return ((readl(SEC_AO_SEC_GP_CFG0) >> 16) & 0xffff); +} |