On Thu, Jun 14, 2012 at 03:43:26PM +0200, Sascha Hauer wrote: ... > +#include <linux/module.h> > +#include <linux/export.h> > +#include <linux/types.h> > +#include <linux/init.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/spinlock.h> > +#include <linux/delay.h> > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/clk.h> > +#include <linux/list.h> > +#include <linux/irq.h> > +#include <mach/common.h> This seems not needed at all. > +#include <drm/imx-ipu-v3.h> > +#include <linux/of_device.h> > +#include <asm/mach/irq.h> ... > +void ipu_ch_param_set_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v) Rename it to ipu_ch_param_write_field ... > +{ > + u32 bit = (wbs >> 8) % 160; > + u32 size = wbs & 0xff; > + u32 word = (wbs >> 8) / 160; > + u32 i = bit / 32; > + u32 ofs = bit % 32; > + u32 mask = (1 << size) - 1; > + u32 val; > + > + pr_debug("%s %d %d %d\n", __func__, word, bit , size); > + > + val = readl(&base->word[word].data[i]); > + val &= ~(mask << ofs); > + val |= v << ofs; > + writel(val, &base->word[word].data[i]); > + > + if ((bit + size - 1) / 32 > i) { > + val = readl(&base->word[word].data[i + 1]); > + val &= ~(mask >> (mask ? (32 - ofs) : 0)); > + val |= v >> (ofs ? (32 - ofs) : 0); > + writel(val, &base->word[word].data[i + 1]); > + } > +} > +EXPORT_SYMBOL_GPL(ipu_ch_param_set_field); > + > +u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs) ... or rename this to ipu_ch_param_get_field for a better couple? > +{ > + u32 bit = (wbs >> 8) % 160; > + u32 size = wbs & 0xff; > + u32 word = (wbs >> 8) / 160; > + u32 i = bit / 32; > + u32 ofs = bit % 32; > + u32 mask = (1 << size) - 1; > + u32 val = 0; > + > + pr_debug("%s %d %d %d\n", __func__, word, bit , size); > + > + val = (readl(&base->word[word].data[i]) >> ofs) & mask; > + > + if ((bit + size - 1) / 32 > i) { > + u32 tmp; > + tmp = readl(&base->word[word].data[i + 1]); > + tmp &= mask >> (ofs ? (32 - ofs) : 0); > + val |= tmp << (ofs ? (32 - ofs) : 0); > + } > + > + return val; > +} > +EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); ... > +static int ipu_reset(struct ipu_soc *ipu) > +{ > + int timeout = 10000; We may want to use a better timeout mechanism. > + > + ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST); > + > + while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) { > + if (!timeout--) > + return -ETIME; > + udelay(100); > + } > + > + mdelay(300); > + > + return 0; > +} ... > +static int ipu_irq_init(struct ipu_soc *ipu) > +{ > + int i; > + > + ipu->irq_start = irq_alloc_descs(-1, 0, IPU_NUM_IRQS, 0); We may want to give a try on linear irqdomain, so that irqdesc will only be allocated for those in-use irqs, and we do not have to maintain irq_base. > + if (ipu->irq_start < 0) > + return ipu->irq_start; > + > + for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) { > + irq_set_chip_and_handler(i, &ipu_irq_chip, handle_level_irq); > + set_irq_flags(i, IRQF_VALID); > + irq_set_chip_data(i, ipu); > + } > + > + irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler); > + irq_set_handler_data(ipu->irq_sync, ipu); > + irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler); > + irq_set_handler_data(ipu->irq_err, ipu); > + > + return 0; > +} ... > +static int __devinit ipu_probe(struct platform_device *pdev) > +{ > + const struct of_device_id *of_id = > + of_match_device(imx_ipu_dt_ids, &pdev->dev); > + struct ipu_soc *ipu; > + struct resource *res; > + unsigned long ipu_base; > + int i, ret, irq_sync, irq_err; > + struct ipu_devtype *devtype; > + > + devtype = of_id->data; > + > + dev_info(&pdev->dev, "Initializing %s\n", devtype->name); > + > + irq_sync = platform_get_irq(pdev, 0); > + irq_err = platform_get_irq(pdev, 1); > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + > + dev_info(&pdev->dev, "irq_sync: %d irq_err: %d\n", > + irq_sync, irq_err); > + > + if (!res || irq_sync < 0 || irq_err < 0) > + return -ENODEV; > + > + ipu_base = res->start; > + > + ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL); > + if (!ipu) > + return -ENODEV; > + > + for (i = 0; i < 64; i++) > + ipu->channel[i].ipu = ipu; > + ipu->devtype = devtype; > + ipu->ipu_type = devtype->type; > + > + spin_lock_init(&ipu->lock); > + mutex_init(&ipu->channel_lock); > + > + dev_info(&pdev->dev, "cm_reg: 0x%08lx\n", > + ipu_base + devtype->cm_ofs); > + dev_info(&pdev->dev, "idmac: 0x%08lx\n", > + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); > + dev_info(&pdev->dev, "cpmem: 0x%08lx\n", > + ipu_base + devtype->cpmem_ofs); > + dev_info(&pdev->dev, "disp0: 0x%08lx\n", > + ipu_base + devtype->disp0_ofs); > + dev_info(&pdev->dev, "disp1: 0x%08lx\n", > + ipu_base + devtype->disp1_ofs); > + dev_info(&pdev->dev, "srm: 0x%08lx\n", > + ipu_base + devtype->srm_ofs); > + dev_info(&pdev->dev, "tpm: 0x%08lx\n", > + ipu_base + devtype->tpm_ofs); > + dev_info(&pdev->dev, "dc: 0x%08lx\n", > + ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS); > + dev_info(&pdev->dev, "ic: 0x%08lx\n", > + ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS); > + dev_info(&pdev->dev, "dmfc: 0x%08lx\n", > + ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS); > + > + ipu->cm_reg = devm_ioremap(&pdev->dev, > + ipu_base + devtype->cm_ofs, PAGE_SIZE); > + ipu->idmac_reg = devm_ioremap(&pdev->dev, > + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, > + PAGE_SIZE); > + ipu->cpmem_base = devm_ioremap(&pdev->dev, > + ipu_base + devtype->cpmem_ofs, PAGE_SIZE); > + > + if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) { > + ret = -ENOMEM; > + goto failed_ioremap; > + } > + > + ipu->clk = devm_clk_get(&pdev->dev, "bus"); > + if (IS_ERR(ipu->clk)) { > + ret = PTR_ERR(ipu->clk); > + dev_err(&pdev->dev, "clk_get failed with %d", ret); > + goto failed_clk_get; > + } > + > + platform_set_drvdata(pdev, ipu); > + > + clk_prepare_enable(ipu->clk); > + > + ipu->dev = &pdev->dev; > + ipu->irq_sync = irq_sync; > + ipu->irq_err = irq_err; > + > + ret = ipu_irq_init(ipu); > + if (ret) > + goto out_failed_irq; > + > + ipu_reset(ipu); > + > + /* Set MCU_T to divide MCU access window into 2 */ > + ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), > + IPU_DISP_GEN); > + > + ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk); > + if (ret) > + goto failed_submodules_init; > + > + ret = ipu_add_client_devices(ipu); > + if (ret) { > + dev_err(&pdev->dev, "adding client devices failed with %d\n", > + ret); > + goto failed_add_clients; > + } > + > + return 0; > + > +failed_add_clients: > + ipu_submodules_exit(ipu); > +failed_submodules_init: > + ipu_irq_exit(ipu); > +out_failed_irq: clk_disable_unprepare(ipu->clk); > +failed_clk_get: > +failed_ioremap: > + return ret; > +} -- Regards, Shawn _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel