⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sa1111.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * 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 + -