static int tegra_gmi_char_prepare_regs(struct tegra_gmi_char_info *info) { struct tegra_nor_chip_parms *chip_parm = info->plat; struct cs_info *csinfo = &chip_parm->csinfo; u32 width = chip_parm->BusWidth; u32 config = 0; config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0); config |= TEGRA_SNOR_CONFIG_SNOR_CS(csinfo->cs); config &= ~TEGRA_SNOR_CONFIG_DEVICE_TYPE; config |= TEGRA_SNOR_CONFIG_WP; /* Enable writes */ switch (width) { case 2: config &= ~TEGRA_SNOR_CONFIG_WORDWIDE; /* 16 bit */ break; case 4: config |= TEGRA_SNOR_CONFIG_WORDWIDE; /* 32 bit */ break; default: return -EINVAL; } switch (chip_parm->MuxMode) { case NorMuxMode_ADNonMux: config &= ~TEGRA_SNOR_CONFIG_MUX_MODE; break; case NorMuxMode_ADMux: config |= TEGRA_SNOR_CONFIG_MUX_MODE; break; default: return -EINVAL; } switch (chip_parm->ReadyActive) { case NorReadyActive_WithData: config &= ~TEGRA_SNOR_CONFIG_RDY_ACTIVE; break; case NorReadyActive_BeforeData: config |= TEGRA_SNOR_CONFIG_RDY_ACTIVE; break; default: return -EINVAL; } info->init_config = config; info->timing0_default = chip_parm->timing_default.timing0; info->timing0_read = chip_parm->timing_read.timing0; info->timing1_default = chip_parm->timing_default.timing1; info->timing1_read = chip_parm->timing_read.timing1; return 0; }
static void tegra_flash_dma(struct map_info *map, void *to, unsigned long from, ssize_t len) { u32 snor_config, dma_config = 0; int dma_transfer_count = 0, word32_count = 0; u32 nor_address, current_transfer = 0; u32 copy_to = (u32)to; struct tegra_nor_info *c = container_of(map, struct tegra_nor_info, map); struct tegra_nor_chip_parms *chip_parm = &c->plat->chip_parms; unsigned int bytes_remaining = len; snor_config = c->init_config; snor_tegra_writel(c, c->timing0_read, TEGRA_SNOR_TIMING0_REG); snor_tegra_writel(c, c->timing1_read, TEGRA_SNOR_TIMING1_REG); if (len > 32) { word32_count = len >> 2; bytes_remaining = len & 0x00000003; /* * The parameters can be setup in any order since we write to * controller register only after all parameters are set. */ /* SNOR CONFIGURATION SETUP */ switch(chip_parm->ReadMode) { case NorReadMode_Async: snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0); break; case NorReadMode_Page: switch(chip_parm->PageLength) { case NorPageLength_Unsupported : snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0); break; case NorPageLength_4Word : snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(1); snor_config |= TEGRA_SNOR_CONFIG_PAGE_SZ(1); break; case NorPageLength_8Word : snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(1); snor_config |= TEGRA_SNOR_CONFIG_PAGE_SZ(2); break; } break; case NorReadMode_Burst: snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(2); switch(chip_parm->BurstLength) { case NorBurstLength_CntBurst : snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(0); break; case NorBurstLength_8Word : snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(1); break; case NorBurstLength_16Word : snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(2); break; case NorBurstLength_32Word : snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(3); break; } break; } snor_config |= TEGRA_SNOR_CONFIG_MST_ENB; /* SNOR DMA CONFIGURATION SETUP */ /* NOR -> AHB */ dma_config &= ~TEGRA_SNOR_DMA_CFG_DIR; /* One word burst */ dma_config |= TEGRA_SNOR_DMA_CFG_BRST_SZ(4); for (nor_address = (unsigned int)(map->phys + from); word32_count > 0; word32_count -= current_transfer, dma_transfer_count += current_transfer, nor_address += (current_transfer * 4), copy_to += (current_transfer * 4)) { current_transfer = (word32_count > TEGRA_SNOR_DMA_LIMIT_WORDS) ? (TEGRA_SNOR_DMA_LIMIT_WORDS) : word32_count; /* Start NOR operation */ snor_config |= TEGRA_SNOR_CONFIG_GO; dma_config |= TEGRA_SNOR_DMA_CFG_GO; /* Enable interrupt before every transaction since the * interrupt handler disables it */ dma_config |= TEGRA_SNOR_DMA_CFG_INT_ENB; /* Num of AHB (32-bit) words to transferred minus 1 */ dma_config |= TEGRA_SNOR_DMA_CFG_WRD_CNT(current_transfer - 1); snor_tegra_writel(c, c->dma_phys_buffer, TEGRA_SNOR_AHB_ADDR_PTR_REG); snor_tegra_writel(c, nor_address, TEGRA_SNOR_NOR_ADDR_PTR_REG); snor_tegra_writel(c, snor_config, TEGRA_SNOR_CONFIG_REG); snor_tegra_writel(c, dma_config, TEGRA_SNOR_DMA_CFG_REG); if (wait_for_dma_completion(c)) { dev_err(c->dev, "timout waiting for DMA\n"); /* Transfer the remaining words by memcpy */ bytes_remaining += (word32_count << 2); break; } dma_sync_single_for_cpu(c->dev, c->dma_phys_buffer, (current_transfer << 2), DMA_FROM_DEVICE); memcpy((char *)(copy_to), (char *)(c->dma_virt_buffer), (current_transfer << 2)); } }