[PATCH 4/5] DRM: add i.MX IPUv3 base driver
Shawn Guo
shawn.guo at linaro.org
Fri Jun 22 02:04:56 EDT 2012
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
More information about the linux-arm-kernel
mailing list