📄 sa1111.c
字号:
* Bring the SA1111 out of reset. This requires a set procedure: * 1. nRESET asserted (by hardware) * 2. CLK turned on from SA1110 * 3. nRESET deasserted * 4. VCO turned on, PLL_BYPASS turned off * 5. Wait lock time, then assert RCLKEn * 7. PCR set to allow clocking of individual functions * * Until we've done this, the only registers we can access are: * SBI_SKCR * SBI_SMCR * SBI_SKID */static void sa1111_wake(struct sa1111 *sachip){ unsigned long flags, r; spin_lock_irqsave(&sachip->lock, flags); clk_enable(sachip->clk); /* * Turn VCO on, and disable PLL Bypass. */ r = sa1111_readl(sachip->base + SA1111_SKCR); r &= ~SKCR_VCO_OFF; sa1111_writel(r, sachip->base + SA1111_SKCR); r |= SKCR_PLL_BYPASS | SKCR_OE_EN; sa1111_writel(r, sachip->base + SA1111_SKCR); /* * Wait lock time. SA1111 manual _doesn't_ * specify a figure for this! We choose 100us. */ udelay(100); /* * Enable RCLK. We also ensure that RDYEN is set. */ r |= SKCR_RCLKEN | SKCR_RDYEN; sa1111_writel(r, sachip->base + SA1111_SKCR); /* * Wait 14 RCLK cycles for the chip to finish coming out * of reset. (RCLK=24MHz). This is 590ns. */ udelay(1); /* * Ensure all clocks are initially off. */ sa1111_writel(0, sachip->base + SA1111_SKPCR); spin_unlock_irqrestore(&sachip->lock, flags);}#ifdef CONFIG_ARCH_SA1100static u32 sa1111_dma_mask[] = { ~0, ~(1 << 20), ~(1 << 23), ~(1 << 24), ~(1 << 25), ~(1 << 20), ~(1 << 20), 0,};/* * Configure the SA1111 shared memory controller. */voidsa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, unsigned int cas_latency){ unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); if (cas_latency == 3) smcr |= SMCR_CLAT; sa1111_writel(smcr, sachip->base + SA1111_SMCR); /* * Now clear the bits in the DMA mask to work around the SA1111 * DMA erratum (Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update, June 2000, Erratum #7). */ if (sachip->dev->dma_mask) *sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2]; sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2];}#endifstatic void sa1111_dev_release(struct device *_dev){ struct sa1111_dev *dev = SA1111_DEV(_dev); release_resource(&dev->res); kfree(dev);}static intsa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, struct sa1111_dev_info *info){ struct sa1111_dev *dev; int ret; dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; goto out; } snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "%4.4lx", info->offset); dev->devid = info->devid; dev->dev.parent = sachip->dev; dev->dev.bus = &sa1111_bus_type; dev->dev.release = sa1111_dev_release; dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask; dev->res.start = sachip->phys + info->offset; dev->res.end = dev->res.start + 511; dev->res.name = dev->dev.bus_id; dev->res.flags = IORESOURCE_MEM; dev->mapbase = sachip->base + info->offset; dev->skpcr_mask = info->skpcr_mask; memmove(dev->irq, info->irq, sizeof(dev->irq)); ret = request_resource(parent, &dev->res); if (ret) { printk("SA1111: failed to allocate resource for %s\n", dev->res.name); kfree(dev); goto out; } ret = device_register(&dev->dev); if (ret) { release_resource(&dev->res); kfree(dev); goto out; } /* * If the parent device has a DMA mask associated with it, * propagate it down to the children. */ if (sachip->dev->dma_mask) { dev->dma_mask = *sachip->dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask; if (dev->dma_mask != 0xffffffffUL) { ret = dmabounce_register_dev(&dev->dev, 1024, 4096); if (ret) { printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id); device_unregister(&dev->dev); } } }out: return ret;}/** * sa1111_probe - probe for a single SA1111 chip. * @phys_addr: physical address of device. * * Probe for a SA1111 chip. This must be called * before any other SA1111-specific code. * * Returns: * %-ENODEV device not found. * %-EBUSY physical address already marked in-use. * %0 successful. */static int__sa1111_probe(struct device *me, struct resource *mem, int irq){ struct sa1111 *sachip; unsigned long id; unsigned int has_devs; int i, ret = -ENODEV; sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL); if (!sachip) return -ENOMEM; sachip->clk = clk_get(me, "GPIO27_CLK"); if (!sachip->clk) { ret = PTR_ERR(sachip->clk); goto err_free; } spin_lock_init(&sachip->lock); sachip->dev = me; dev_set_drvdata(sachip->dev, sachip); sachip->phys = mem->start; sachip->irq = irq; /* * Map the whole region. This also maps the * registers for our children. */ sachip->base = ioremap(mem->start, PAGE_SIZE * 2); if (!sachip->base) { ret = -ENOMEM; goto err_clkput; } /* * Probe for the chip. Only touch the SBI registers. */ id = sa1111_readl(sachip->base + SA1111_SKID); if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); ret = -ENODEV; goto err_unmap; } printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " "silicon revision %lx, metal revision %lx\n", (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); /* * We found it. Wake the chip up, and initialise. */ sa1111_wake(sachip);#ifdef CONFIG_ARCH_SA1100 { unsigned int val; /* * The SDRAM configuration of the SA1110 and the SA1111 must * match. This is very important to ensure that SA1111 accesses * don't corrupt the SDRAM. Note that this ungates the SA1111's * MBGNT signal, so we must have called sa1110_mb_disable() * beforehand. */ sa1111_configure_smc(sachip, 1, FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); /* * We only need to turn on DCLK whenever we want to use the * DMA. It can otherwise be held firmly in the off position. * (currently, we always enable it.) */ val = sa1111_readl(sachip->base + SA1111_SKPCR); sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); /* * Enable the SA1110 memory bus request and grant signals. */ sa1110_mb_enable(); }#endif /* * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available. */ if (sachip->irq != NO_IRQ) sa1111_setup_irq(sachip); g_sa1111 = sachip; has_devs = ~0; if (machine_is_assabet() || machine_is_jornada720() || machine_is_badge4()) has_devs &= ~(1 << 4); else has_devs &= ~(1 << 1); for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) if (has_devs & (1 << i)) sa1111_init_one_child(sachip, mem, &sa1111_devices[i]); return 0; err_unmap: iounmap(sachip->base); err_clkput: clk_put(sachip->clk); err_free: kfree(sachip); return ret;}static int sa1111_remove_one(struct device *dev, void *data){ device_unregister(dev); return 0;}static void __sa1111_remove(struct sa1111 *sachip){ void __iomem *irqbase = sachip->base + SA1111_INTC; device_for_each_child(sachip->dev, NULL, sa1111_remove_one); /* disable all IRQs */ sa1111_writel(0, irqbase + SA1111_INTEN0); sa1111_writel(0, irqbase + SA1111_INTEN1); sa1111_writel(0, irqbase + SA1111_WAKEEN0); sa1111_writel(0, irqbase + SA1111_WAKEEN1); clk_disable(sachip->clk); if (sachip->irq != NO_IRQ) { set_irq_chained_handler(sachip->irq, NULL); set_irq_data(sachip->irq, NULL); release_mem_region(sachip->phys + SA1111_INTC, 512); } iounmap(sachip->base); clk_put(sachip->clk); kfree(sachip);}/* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If * an access to a region of memory above 1MB relative to the bank base, * it is important that address bit 10 _NOT_ be asserted. Depending * on the configuration of the RAM, bit 10 may correspond to one * of several different (processor-relative) address bits. * * This routine only identifies whether or not a given DMA address * is susceptible to the bug. * * This should only get called for sa1111_device types due to the * way we configure our device dma_masks. */int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size){ /* * Section 4.6 of the "Intel StrongARM SA-1111 Development Module * User's Guide" mentions that jumpers R51 and R52 control the * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * SDRAM bank 1 on Neponset). The default configuration selects * Assabet, so any address in bank 1 is necessarily invalid. */ return ((machine_is_assabet() || machine_is_pfs168()) && (addr >= 0xc8000000 || (addr + size) >= 0xc8000000));}struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; unsigned int skcdr; unsigned char skaud; unsigned char skpwm0; unsigned char skpwm1; /* * Interrupt controller */ unsigned int intpol0; unsigned int intpol1; unsigned int inten0; unsigned int inten1; unsigned int wakepol0; unsigned int wakepol1; unsigned int wakeen0; unsigned int wakeen1;};#ifdef CONFIG_PMstatic int sa1111_suspend(struct platform_device *dev, pm_message_t state){ struct sa1111 *sachip = platform_get_drvdata(dev); struct sa1111_save_data *save; unsigned long flags; unsigned int val; void __iomem *base; save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); if (!save) return -ENOMEM; sachip->saved_state = save; spin_lock_irqsave(&sachip->lock, flags); /* * Save state. */ base = sachip->base; save->skcr = sa1111_readl(base + SA1111_SKCR); save->skpcr = sa1111_readl(base + SA1111_SKPCR); save->skcdr = sa1111_readl(base + SA1111_SKCDR); save->skaud = sa1111_readl(base + SA1111_SKAUD); save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); base = sachip->base + SA1111_INTC; save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); save->inten0 = sa1111_readl(base + SA1111_INTEN0); save->inten1 = sa1111_readl(base + SA1111_INTEN1); save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0); save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1); save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0); save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1); /* * Disable. */ val = sa1111_readl(sachip->base + SA1111_SKCR); sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); sa1111_writel(0, sachip->base + SA1111_SKPWM0); sa1111_writel(0, sachip->base + SA1111_SKPWM1); clk_disable(sachip->clk); spin_unlock_irqrestore(&sachip->lock, flags); return 0;}/* * sa1111_resume - Restore the SA1111 device state. * @dev: device to restore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -