static void pca_gmi_writebyte(void *pd, int reg, int val) { struct tegra_nor_chip_parms *chip_parm = info->plat; struct cs_info *csinfo = &chip_parm->csinfo; unsigned int *ptr = csinfo->virt; struct gpio_state *state = &csinfo->gpio_cs; snor_tegra_writel(info, info->init_config, TEGRA_SNOR_CONFIG_REG); snor_tegra_writel(info, info->timing1_read, TEGRA_SNOR_TIMING1_REG); snor_tegra_writel(info, info->timing0_read, TEGRA_SNOR_TIMING0_REG); gpio_set_value(state[0].gpio_num, state[0].value); __raw_writeb(val, ptr + reg); }
static ssize_t gmichar_chrdev_write_helper(unsigned int *dest, char *src, size_t size) { int i; snor_tegra_writel(info, info->init_config, TEGRA_SNOR_CONFIG_REG); snor_tegra_writel(info, info->timing1_read, TEGRA_SNOR_TIMING1_REG); snor_tegra_writel(info, info->timing0_read, TEGRA_SNOR_TIMING0_REG); udelay(1); for (i = 0; i < size; i++) __raw_writeb(src[i], dest + i); udelay(1); return size; }
static ssize_t gmichar_chrdev_read_helper(char *dest, int *src, size_t size) { int i; snor_tegra_writel(info, info->init_config, TEGRA_SNOR_CONFIG_REG); snor_tegra_writel(info, info->timing1_read, TEGRA_SNOR_TIMING1_REG); snor_tegra_writel(info, info->timing0_read, TEGRA_SNOR_TIMING0_REG); udelay(1); for (i = 0; i < size; i++) dest[i] = __raw_readb(src + i); udelay(1); return size; }
static int __init tegra_gmi_char_probe(struct platform_device *pdev) { int err = -ENODEV; struct tegra_nor_chip_parms *plat = pdev->dev.platform_data; struct device *dev = &pdev->dev; if (!plat) { pr_err("%s: no platform device info\n", __func__); return -EINVAL; } info = devm_kzalloc(dev, sizeof(struct tegra_gmi_char_info), GFP_KERNEL); if (!info) return -ENOMEM; info->base = ((void __iomem *)IO_APB_VIRT + (TEGRA_SNOR_BASE - IO_APB_PHYS)); info->plat = plat; info->dev = dev; #ifdef CONFIG_TEGRA_GMI_ACCESS_CONTROL info->gmiLockHandle = register_gmi_device(DRV_NAME, 0); info->request_gmi_access = request_gmi_access; info->release_gmi_access = release_gmi_access; info->gmiLockHandle = register_gmi_device(DRV_NAME, 0); #else info->gmiLockHandle = NULL; info->request_gmi_access = NULL; info->release_gmi_access = NULL; #endif /* Clock setting */ info->clk = clk_get_sys("tegra-nor", NULL); if (IS_ERR(info->clk)) { pr_err("%s: can't get clock\n", __func__); return PTR_ERR(info->clk); } err = clk_prepare_enable(info->clk); if (err != 0) { pr_err("%s: can't enable clock\n", __func__); return err; } err = tegra_gmi_char_prepare_regs(info); if (err) { dev_err(dev, "Error initializing reg values\n"); return err; } // write init config snor_tegra_writel(info, info->init_config, TEGRA_SNOR_CONFIG_REG); snor_tegra_writel(info, info->timing1_read, TEGRA_SNOR_TIMING1_REG); snor_tegra_writel(info, info->timing0_read, TEGRA_SNOR_TIMING0_REG); platform_set_drvdata(pdev, info); info->gmi_class = class_create(THIS_MODULE, DRV_NAME); if (IS_ERR(info->gmi_class)) { err = PTR_ERR(info->gmi_class); return err; } err = alloc_chrdev_region(&info->gmi_dev_t, 0, 1, DRV_NAME); if (err < 0) { class_destroy(info->gmi_class); pr_err("%s: failed to allocate device region\n", DRV_NAME); return err; } cdev_init(&info->gmi_cdev, &gmichar_fops); err = cdev_add(&info->gmi_cdev, info->gmi_dev_t, 1); if (err) return err; info->gmi_device = device_create(info->gmi_class, NULL, info->gmi_dev_t, info, DRV_NAME); if (IS_ERR(info->gmi_device)) { pr_err("device create failed for %s\n", DRV_NAME); cdev_del(&info->gmi_cdev); goto fail; } return 0; fail: pr_err("Tegra GMI CHAR probe failed\n"); return err; }
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)); } }