// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/common/sa1111.c * * SA1111 support * * Original code by John Dorsey * * This file contains all generic SA1111 support. * * All initialization functions provided here are intended to be called * from machine specific code with proper arguments when required.
*/ #include <linux/module.h> #include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/dma-map-ops.h> #include <linux/clk.h> #include <linux/io.h>
/* * We keep the following data for the overall SA1111. Note that the * struct device and struct resource are "fake"; they should be supplied * by the bus above us. However, in the interests of getting all SA1111 * drivers converted over to the device model, we provide this as an * anchor point for all the other drivers.
*/ struct sa1111 { struct device *dev; struct clk *clk; unsignedlong phys; int irq; int irq_base; /* base for cascaded on-chip IRQs */
spinlock_t lock; void __iomem *base; struct sa1111_platform_data *pdata; struct irq_domain *irqdomain; struct gpio_chip gc; #ifdef CONFIG_PM void *saved_state; #endif
};
/* * We _really_ need to eliminate this. Its only users * are the PWM and DMA checking code.
*/ staticstruct sa1111 *g_sa1111;
/* * SA1111 interrupt support. Since clearing an IRQ while there are * active IRQs causes the interrupt output to pulse, the upper levels * will call us again if there are more interrupts to process.
*/ staticvoid sa1111_irq_handler(struct irq_desc *desc)
{ unsignedint stat0, stat1, i; struct sa1111 *sachip = irq_desc_get_handler_data(desc); struct irq_domain *irqdomain; void __iomem *mapbase = sachip->base + SA1111_INTC;
/* * Attempt to re-trigger the interrupt. The SA1111 contains a register * (INTSET) which claims to do this. However, in practice no amount of * manipulation of INTEN and INTSET guarantees that the interrupt will * be triggered. In fact, its very difficult, if not impossible to get * INTSET to re-trigger the interrupt.
*/ staticint sa1111_retrigger_irq(struct irq_data *d)
{ struct sa1111 *sachip = irq_data_get_irq_chip_data(d); void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d);
u32 ip, mask = sa1111_irqmask(d); int i;
ip = readl_relaxed(mapbase + SA1111_INTPOL0); for (i = 0; i < 8; i++) {
writel_relaxed(ip ^ mask, mapbase + SA1111_INTPOL0);
writel_relaxed(ip, mapbase + SA1111_INTPOL0); if (readl_relaxed(mapbase + SA1111_INTSTATCLR0) & mask) break;
}
if (i == 8) {
pr_err("Danger Will Robinson: failed to re-trigger IRQ%d\n",
d->irq); return 0;
}
irq_set_chained_handler_and_data(sachip->irq, NULL, NULL); for (i = 0; i < SA1111_IRQ_NR; i++)
irq_dispose_mapping(irq_find_mapping(domain, i));
irq_domain_remove(domain);
/* * 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
*/ staticvoid sa1111_wake(struct sa1111 *sachip)
{ unsignedlong flags, r;
spin_lock_irqsave(&sachip->lock, flags);
clk_enable(sachip->clk);
/* * Turn VCO on, and disable PLL Bypass.
*/
r = readl_relaxed(sachip->base + SA1111_SKCR);
r &= ~SKCR_VCO_OFF;
writel_relaxed(r, sachip->base + SA1111_SKCR);
r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
writel_relaxed(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;
writel_relaxed(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.
*/
writel_relaxed(0, sachip->base + SA1111_SKPCR);
/* * 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];
for (i = 0; i < ARRAY_SIZE(info->hwirq); i++)
dev->hwirq[i] = info->hwirq[i];
/* * If the parent device has a DMA mask associated with it, and * this child supports DMA, propagate it down to the children.
*/ if (info->dma && sachip->dev->dma_mask) {
dev->dma_mask = *sachip->dev->dma_mask;
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
}
ret = request_resource(parent, &dev->res); if (ret) {
dev_err(sachip->dev, "failed to allocate resource for %s\n",
dev->res.name); goto err_resource;
}
ret = device_add(&dev->dev); if (ret) goto err_add; return 0;
/* * 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_clk_unprep;
}
/* * Probe for the chip. Only touch the SBI registers.
*/
id = readl_relaxed(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;
}
pr_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);
/* * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available.
*/
ret = sa1111_setup_irq(sachip, pd->irq_base); if (ret) goto err_clk;
/* Setup the GPIOs - should really be done after the IRQ setup */
ret = sa1111_setup_gpios(sachip); if (ret) goto err_irq;
#ifdef CONFIG_ARCH_SA1100
{ unsignedint 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 = readl_relaxed(sachip->base + SA1111_SKPCR);
writel_relaxed(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR);
/* * Enable the SA1110 memory bus request and grant signals.
*/
sa1110_mb_enable();
} #endif
g_sa1111 = sachip;
has_devs = ~0; if (pd)
has_devs &= ~pd->disable_devs;
for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++) if (sa1111_devices[i].devid & has_devs)
sa1111_init_one_child(sachip, mem, &sa1111_devices[i]);
/* * sa1111_resume - Restore the SA1111 device state. * @dev: device to restore * * Restore the general state of the SA1111; clock control and * interrupt controller. Other parts of the SA1111 must be * restored by their respective drivers, and must be called * via LDM after this function.
*/ staticint sa1111_resume_noirq(struct device *dev)
{ struct sa1111 *sachip = dev_get_drvdata(dev); struct sa1111_save_data *save; unsignedlong flags, id; void __iomem *base;
save = sachip->saved_state; if (!save) return 0;
/* * Ensure that the SA1111 is still here. * FIXME: shouldn't do this here.
*/
id = readl_relaxed(sachip->base + SA1111_SKID); if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
__sa1111_remove(sachip);
dev_set_drvdata(dev, NULL);
kfree(save); return 0;
}
/* * First of all, wake up the chip.
*/
sa1111_wake(sachip);
#ifdef CONFIG_ARCH_SA1100 /* Enable the memory bus request/grant signals */
sa1110_mb_enable(); #endif
/* * Only lock for write ops. Also, sa1111_wake must be called with * released spinlock!
*/
spin_lock_irqsave(&sachip->lock, flags);
base = sachip->base;
writel_relaxed(save->skcr, base + SA1111_SKCR);
writel_relaxed(save->skpcr, base + SA1111_SKPCR);
writel_relaxed(save->skcdr, base + SA1111_SKCDR);
writel_relaxed(save->skaud, base + SA1111_SKAUD);
writel_relaxed(save->skpwm0, base + SA1111_SKPWM0);
writel_relaxed(save->skpwm1, base + SA1111_SKPWM1);
base = sachip->base + SA1111_INTC;
writel_relaxed(save->intpol0, base + SA1111_INTPOL0);
writel_relaxed(save->intpol1, base + SA1111_INTPOL1);
writel_relaxed(save->inten0, base + SA1111_INTEN0);
writel_relaxed(save->inten1, base + SA1111_INTEN1);
writel_relaxed(save->wakepol0, base + SA1111_WAKEPOL0);
writel_relaxed(save->wakepol1, base + SA1111_WAKEPOL1);
writel_relaxed(save->wakeen0, base + SA1111_WAKEEN0);
writel_relaxed(save->wakeen1, base + SA1111_WAKEEN1);
/* * Not sure if this should be on the system bus or not yet. * We really want some way to register a system device at * the per-machine level, and then have this driver pick * up the registered devices. * * We also need to handle the SDRAM configuration for * PXA250/SA1110 machine classes.
*/ staticstruct platform_driver sa1111_device_driver = {
.probe = sa1111_probe,
.remove = sa1111_remove,
.driver = {
.name = "sa1111",
.pm = &sa1111_pm_ops,
},
};
/* * Get the parent device driver (us) structure * from a child function device
*/ staticinlinestruct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
{ return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent);
}
/* * The bits in the opdiv field are non-linear.
*/ staticunsignedchar opdiv_table[] = { 1, 4, 2, 8 };
/** * sa1111_pll_clock - return the current PLL clock frequency. * @sadev: SA1111 function block * * BUG: we should look at SKCR. We also blindly believe that * the chip is being fed with the 3.6864MHz clock. * * Returns the PLL clock in Hz.
*/ unsignedint sa1111_pll_clock(struct sa1111_dev *sadev)
{ struct sa1111 *sachip = sa1111_chip_driver(sadev);
/** * sa1111_select_audio_mode - select I2S or AC link mode * @sadev: SA1111 function block * @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S * * Frob the SKCR to select AC Link mode or I2S mode for * the audio block.
*/ void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode)
{ struct sa1111 *sachip = sa1111_chip_driver(sadev); unsignedlong flags; unsignedint val;
spin_lock_irqsave(&sachip->lock, flags);
val = readl_relaxed(sachip->base + SA1111_SKCR); if (mode == SA1111_AUDIO_I2S) {
val &= ~SKCR_SELAC;
} else {
val |= SKCR_SELAC;
}
writel_relaxed(val, sachip->base + SA1111_SKCR);
/* * SA1111 "Register Access Bus." * * We model this as a regular bus type, and hang devices directly * off this.
*/ staticint sa1111_match(struct device *_dev, conststruct device_driver *_drv)
{ struct sa1111_dev *dev = to_sa1111_device(_dev); conststruct sa1111_driver *drv = SA1111_DRV(_drv);
return !!(dev->devid & drv->devid);
}
staticint sa1111_bus_probe(struct device *dev)
{ struct sa1111_dev *sadev = to_sa1111_device(dev); struct sa1111_driver *drv = SA1111_DRV(dev->driver); int ret = -ENODEV;
if (drv->probe)
ret = drv->probe(sadev); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.