// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include "nfc.h" #include "linux/amlogic/aml_pageinfo.h" #include struct regmap *nfc_regmap[3]; struct nfc_clk_provider clk_provider[MAX_CLK_PROVIDER] = { {OSC_CLK_24MHZ, CLK_6MHZ, 1, 4, 0, 1}, {OSC_CLK_24MHZ, CLK_12MHZ, 1, 2, 0, 2}, {FIX_PLL_DIV2, CLK_20MHZ, 12, 4, 0, 3}, {FIX_PLL_DIV2, CLK_41MHZ, 6, 4, 0, 5}, {FIX_PLL_DIV2, CLK_83MHZ, 3, 4, 1, 7}, {FIX_PLL_DIV2P5, CLK_100MHZ_400, 2, 4, 0, 11}, {FIX_PLL_DIV2, CLK_100MHZ_500, 2, 5, 0, 11}, {FIX_PLL_DIV2, CLK_125MHZ, 2, 4, 0, 13}, {FIX_PLL_DIV2P5, CLK_133MHZ, 2, 3, 0, 13}, {FIX_PLL_DIV2, CLK_166MHZ_333, 3, 2, 0, 15}, {FIX_PLL_DIV3, CLK_166MHZ_666, 1, 4, 0, 15}, {FIX_PLL_DIV2P5, CLK_200MHZ_400, 2, 2, 0, 21}, {FIX_PLL_DIV2P5, CLK_200MHZ_800, 1, 4, 0, 21}, }; struct nfc_clk_provider *g_clk_info = &clk_provider[CLK_83MHZ]; unsigned int nfc_recalculate_n2m_command(u32 size, int no_cal) { u32 n2m_cmd, page_size; int ecc_size; page_size = page_info_get_page_size(); n2m_cmd = page_info_get_n2m_command(); if (no_cal) return n2m_cmd; if (size == page_size) return n2m_cmd; ecc_size = (GET_BCH_MODE(n2m_cmd) == 1) ? 512 : 1024; size = (size + ecc_size - 1) & (~(ecc_size - 1)); n2m_cmd &= ~0x3F; while (size >= ecc_size) { n2m_cmd++; size -= ecc_size; } return n2m_cmd; } #define NFC_CMD_GET_SIZE(x) (((x) >> 22) & GENMASK(4, 0)) int nfc_wait_command_fifo_done(u32 timeout, int repeat_rb) { u32 cmd_size = 0; int ret = 0; regmap_read(nfc_regmap[NFC_IDX], NAND_CMD, &cmd_size); while (NFC_CMD_GET_SIZE(cmd_size)) regmap_read(nfc_regmap[NFC_IDX], NAND_CMD, &cmd_size); return ret; } void nfc_raw_size_ext_convert(u32 size) { unsigned int raw_ext; regmap_read(nfc_regmap[NFC_IDX], SPI_CFG, &raw_ext); raw_ext &= ~(0xFFF << 18); raw_ext |= ((size >> NFC_RAW_CHUNK_SHIFT) << 18); regmap_write(nfc_regmap[NFC_IDX], SPI_CFG, raw_ext); regmap_read(nfc_regmap[NFC_IDX], SPI_CFG, &raw_ext); NFC_Print("SPI_CFG = 0x%x\n", raw_ext); } #define is_fixpll_locked() (1) #define IS_FEAT_EN_83MHZ_SPI() (0) #define IS_FEAT_EN_41MHZ_SPI() (1) #define IS_FEAT_EN_25MHZ_NAND() (1) #define otp_get_nfc_rxadj(x) ((*(x)) = 0) static struct nfc_clk_provider *nfc_get_clock_provider(void) { struct nfc_clk_provider *clk_info; unsigned char frequency_idx, cs_deselect_time; frequency_idx = page_info_get_frequency_index(); if (frequency_idx == 0xFF) { clk_info = &clk_provider[CLK_83MHZ]; } else { clk_info = &clk_provider[frequency_idx & 0x7F]; if (frequency_idx & 0x80) { clk_info->div1 = page_info_get_core_div(); clk_info->div2 = page_info_get_bus_cycle(); } } cs_deselect_time = page_info_get_cs_deselect_time(); if (cs_deselect_time != 0xFF) { clk_info->cs_deselect_time = cs_deselect_time; NFC_Print("clk_info->cs_deselect_time = 0x%x\n", clk_info->cs_deselect_time); } g_clk_info = clk_info; return clk_info; } void nfc_set_clock_and_timing(unsigned long *clk_rate) { struct nfc_clk_provider *clk_info; unsigned char data_lanes, cmd_lanes, addr_lanes, mode; u32 value, line_delay1, line_delay2; clk_info = nfc_get_clock_provider(); NFC_Print("clock_index = 0x%x\n", clk_info->clk_rate); line_delay1 = page_info_get_line_delay1(); line_delay2 = page_info_get_line_delay2(); data_lanes = page_info_get_data_lanes_mode(); cmd_lanes = page_info_get_cmd_lanes_mode(); addr_lanes = page_info_get_addr_lanes_mode(); mode = page_info_get_work_mode(); // SD_EMMC_DLY1/2 regmap_write(nfc_regmap[EMMC_IDX], SD_EMMC_DLY1, line_delay1); regmap_write(nfc_regmap[EMMC_IDX], SD_EMMC_DLY2, line_delay2); regmap_read(nfc_regmap[EMMC_IDX], 0, &value); regmap_write(nfc_regmap[EMMC_IDX], 0, value | (1 << 6)); value = data_lanes | (cmd_lanes << 2) | ((clk_info->adj & 0x0F) << 4) | (3 << 12) | (mode << 14) | (addr_lanes << 16) | (1 << 31); regmap_write(nfc_regmap[NFC_IDX], SPI_CFG, value); regmap_write(nfc_regmap[NFC_IDX], NAND_CFG, (clk_info->div2 - 1) | (3 << 5) | (1 << 31)); regmap_read(nfc_regmap[NFC_IDX], SPI_CFG, &value); NFC_Print("SPI_CFG = 0x%x\n", value); regmap_read(nfc_regmap[NFC_IDX], NAND_CFG, &value); NFC_Print("NAND_CFG = 0x%x\n", value); *clk_rate = 1000000000 / clk_info->div1; } void nfc_set_data_bus_width(int bus_width) { u32 spi_cfg; regmap_read(nfc_regmap[NFC_IDX], SPI_CFG, &spi_cfg); spi_cfg &= (~0x03); spi_cfg |= bus_width; regmap_write(nfc_regmap[NFC_IDX], SPI_CFG, spi_cfg); regmap_read(nfc_regmap[NFC_IDX], SPI_CFG, &spi_cfg); NFC_Print("SPI_CFG = 0x%x\n", spi_cfg); } u32 nfc_send_cmd_addr_and_wait(unsigned char cmd_bitmap, u8 cmd, u8 *addr, u8 addr_len, u8 *data, u8 data_len, unsigned short state_dummy_ctl) { u8 *buffer = data, dummy_cycles = 0, com_cmd; enum CMD_TYPE cmd_type; enum STATE_AND_DUMMY_CTL action; int i = 0, j = 0, ret; unsigned int reg_value; if (((cmd_bitmap & TYPE_ADDR) && !addr) || ((cmd_bitmap & TYPE_DATA_DRD) && !buffer) || ((cmd_bitmap & TYPE_DATA_DWR) && !buffer) || cmd_bitmap == 0) return ERR_NFC_WRONG_PARAM; action = (state_dummy_ctl >> STATE_AND_DUMMY_CTL_BIT_SHIFT); NFC_Print("cs_deselect_time = 0x%x\n", g_clk_info->cs_deselect_time); if (cmd) regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CEF | IDLE | g_clk_info->cs_deselect_time); while (cmd_bitmap != 0 && i < 8) { cmd_type = CMD_BITMAP_TEST_AND_GET_BIT_VALUE(cmd_bitmap, i); CMD_BITMAP_CLEAR_BIT(cmd_bitmap, i); switch (cmd_type) { case TYPE_NONE: /* skip the zero */ break; case TYPE_CMD: NFC_Print("TYPE_CMD = 0x%x\n", CE0 | CLE | cmd); if (action & DONT_SEND_CEF) { com_cmd = ~cmd; regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | CLE | com_cmd); } regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | CLE | cmd); break; case TYPE_ADDR: if (state_dummy_ctl & 0xFF) dummy_cycles = (state_dummy_ctl & 0xFF) - 1; NFC_Print("dummy_cycles = 0x%x\n", dummy_cycles); if (action & DUMMY_BEFORE_ADDRESS) regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | DUMMY | dummy_cycles); addr += addr_len - 1; NFC_Print("TYPE_ADDR: "); for (j = 0; j < addr_len; j++, addr--) { NFC_Print("0x%x ", CE0 | ALE | *addr); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | ALE | *addr); } NFC_Print("\n"); if (action & DUMMY_AFTER_ADDRESS) regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | DUMMY | dummy_cycles); break; case TYPE_DATA_DRD: NFC_Print("TYPE_DATA_DRD\n"); for (j = 0; j < data_len; j++, buffer++) { regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | DRD | 0); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); ret = nfc_wait_command_fifo_done(NFC_COMMAND_FIFO_TIMEOUT, 0); if (ret) return ret; regmap_read(nfc_regmap[NFC_IDX], NAND_BUF, ®_value); *buffer = reg_value; } return 0; case TYPE_DATA_DWR: NFC_Print("TYPE_DATA_DWR\n"); for (j = 0; j < data_len; j++, buffer++) { regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE | 10); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | DWR | *buffer); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE | 10); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); ret = nfc_wait_command_fifo_done(NFC_COMMAND_FIFO_TIMEOUT, 0); if (ret) return ret; } return 0; default: break; } regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); i++; } return nfc_wait_command_fifo_done(NFC_COMMAND_FIFO_TIMEOUT, 0); } void nfc_set_dma_mem_and_info(u32 mem, unsigned long info) { u32 cmd; cmd = GENCMDDADDRL(NFC_CMD_ADL, mem); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, cmd); cmd = GENCMDDADDRH(NFC_CMD_ADH, mem); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, cmd); cmd = GENCMDIADDRL(NFC_CMD_AIL, info); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, cmd); cmd = GENCMDIADDRH(NFC_CMD_AIH, info); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, cmd); } int nfc_start_dma_and_wait_done(u32 n2m_cmd) { regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, n2m_cmd); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, CE0 | IDLE); return nfc_wait_command_fifo_done(NFC_DATA_FIFO_TIMEOUT, 0); } void nfc_set_user_byte(u8 *oob_buf, u64 *info_buf, int ecc_steps) { u64 *info; int i, count; for (i = 0, count = 0; i < ecc_steps; i++, count += 2) { info = &info_buf[i]; *info |= oob_buf[count]; *info |= oob_buf[count + 1] << 8; } } void nfc_get_user_byte(u8 *oob_buf, u64 *info_buf, int ecc_steps) { u64 *info; int i, count; for (i = 0, count = 0; i < ecc_steps; i++, count += 2) { info = &info_buf[i]; oob_buf[count] = *info; oob_buf[count + 1] = *info >> 8; } } int nfc_wait_data_and_ecc_engine_done(struct device *dev, dma_addr_t iaddr, u64 *info_buf, unsigned char nsteps, int raw) { volatile u64 *info; int i, count = 0; int info_len = nsteps * 8; if (nsteps < 1) return ERR_NFC_WRONG_PARAM; info = info_buf + nsteps - 1; while (count <= 10000) { //usleep_range(10, 15); /* info is updated by nfc dma engine*/ smp_rmb(); dma_sync_single_for_cpu(dev, iaddr, info_len, DMA_FROM_DEVICE); if (*info & ECC_COMPLETE) break; if (count == 10000) { regmap_write(nfc_regmap[NFC_IDX], NAND_CMD, 1 << 31); return ERR_DMA_TIMEOUT; } count++; } if (raw) return 0; for (i = 0, info = info_buf; i < nsteps; i++, info++) { if (ECC_ERR_CNT(*info) != ECC_UNCORRECTABLE) continue; if (ECC_ZERO_CNT(*info) < 0x0a) return 0; return ERROR_ECC; } return 0; }