0001
0002
0003
0004
0005
0006 #include <drm/drm_fourcc.h>
0007 #include <linux/clk.h>
0008 #include <linux/err.h>
0009 #include <linux/iopoll.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/pm_runtime.h>
0016 #include <linux/regmap.h>
0017 #include <video/imx-ipu-v3.h>
0018
0019 #include "ipu-prv.h"
0020
0021 #define IPU_PRG_CTL 0x00
0022 #define IPU_PRG_CTL_BYPASS(i) (1 << (0 + i))
0023 #define IPU_PRG_CTL_SOFT_ARID_MASK 0x3
0024 #define IPU_PRG_CTL_SOFT_ARID_SHIFT(i) (8 + i * 2)
0025 #define IPU_PRG_CTL_SOFT_ARID(i, v) ((v & 0x3) << (8 + 2 * i))
0026 #define IPU_PRG_CTL_SO(i) (1 << (16 + i))
0027 #define IPU_PRG_CTL_VFLIP(i) (1 << (19 + i))
0028 #define IPU_PRG_CTL_BLOCK_MODE(i) (1 << (22 + i))
0029 #define IPU_PRG_CTL_CNT_LOAD_EN(i) (1 << (25 + i))
0030 #define IPU_PRG_CTL_SOFTRST (1 << 30)
0031 #define IPU_PRG_CTL_SHADOW_EN (1 << 31)
0032
0033 #define IPU_PRG_STATUS 0x04
0034 #define IPU_PRG_STATUS_BUFFER0_READY(i) (1 << (0 + i * 2))
0035 #define IPU_PRG_STATUS_BUFFER1_READY(i) (1 << (1 + i * 2))
0036
0037 #define IPU_PRG_QOS 0x08
0038 #define IPU_PRG_QOS_ARID_MASK 0xf
0039 #define IPU_PRG_QOS_ARID_SHIFT(i) (0 + i * 4)
0040
0041 #define IPU_PRG_REG_UPDATE 0x0c
0042 #define IPU_PRG_REG_UPDATE_REG_UPDATE (1 << 0)
0043
0044 #define IPU_PRG_STRIDE(i) (0x10 + i * 0x4)
0045 #define IPU_PRG_STRIDE_STRIDE_MASK 0x3fff
0046
0047 #define IPU_PRG_CROP_LINE 0x1c
0048
0049 #define IPU_PRG_THD 0x20
0050
0051 #define IPU_PRG_BADDR(i) (0x24 + i * 0x4)
0052
0053 #define IPU_PRG_OFFSET(i) (0x30 + i * 0x4)
0054
0055 #define IPU_PRG_ILO(i) (0x3c + i * 0x4)
0056
0057 #define IPU_PRG_HEIGHT(i) (0x48 + i * 0x4)
0058 #define IPU_PRG_HEIGHT_PRE_HEIGHT_MASK 0xfff
0059 #define IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT 0
0060 #define IPU_PRG_HEIGHT_IPU_HEIGHT_MASK 0xfff
0061 #define IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT 16
0062
0063 struct ipu_prg_channel {
0064 bool enabled;
0065 int used_pre;
0066 };
0067
0068 struct ipu_prg {
0069 struct list_head list;
0070 struct device *dev;
0071 int id;
0072
0073 void __iomem *regs;
0074 struct clk *clk_ipg, *clk_axi;
0075 struct regmap *iomuxc_gpr;
0076 struct ipu_pre *pres[3];
0077
0078 struct ipu_prg_channel chan[3];
0079 };
0080
0081 static DEFINE_MUTEX(ipu_prg_list_mutex);
0082 static LIST_HEAD(ipu_prg_list);
0083
0084 struct ipu_prg *
0085 ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
0086 {
0087 struct device_node *prg_node = of_parse_phandle(dev->of_node,
0088 name, 0);
0089 struct ipu_prg *prg;
0090
0091 mutex_lock(&ipu_prg_list_mutex);
0092 list_for_each_entry(prg, &ipu_prg_list, list) {
0093 if (prg_node == prg->dev->of_node) {
0094 mutex_unlock(&ipu_prg_list_mutex);
0095 device_link_add(dev, prg->dev,
0096 DL_FLAG_AUTOREMOVE_CONSUMER);
0097 prg->id = ipu_id;
0098 of_node_put(prg_node);
0099 return prg;
0100 }
0101 }
0102 mutex_unlock(&ipu_prg_list_mutex);
0103
0104 of_node_put(prg_node);
0105
0106 return NULL;
0107 }
0108
0109 int ipu_prg_max_active_channels(void)
0110 {
0111 return ipu_pre_get_available_count();
0112 }
0113 EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
0114
0115 bool ipu_prg_present(struct ipu_soc *ipu)
0116 {
0117 if (ipu->prg_priv)
0118 return true;
0119
0120 return false;
0121 }
0122 EXPORT_SYMBOL_GPL(ipu_prg_present);
0123
0124 bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
0125 uint64_t modifier)
0126 {
0127 const struct drm_format_info *info = drm_format_info(format);
0128
0129 if (info->num_planes != 1)
0130 return false;
0131
0132 switch (modifier) {
0133 case DRM_FORMAT_MOD_LINEAR:
0134 case DRM_FORMAT_MOD_VIVANTE_TILED:
0135 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
0136 return true;
0137 default:
0138 return false;
0139 }
0140 }
0141 EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
0142
0143 int ipu_prg_enable(struct ipu_soc *ipu)
0144 {
0145 struct ipu_prg *prg = ipu->prg_priv;
0146
0147 if (!prg)
0148 return 0;
0149
0150 return pm_runtime_get_sync(prg->dev);
0151 }
0152 EXPORT_SYMBOL_GPL(ipu_prg_enable);
0153
0154 void ipu_prg_disable(struct ipu_soc *ipu)
0155 {
0156 struct ipu_prg *prg = ipu->prg_priv;
0157
0158 if (!prg)
0159 return;
0160
0161 pm_runtime_put(prg->dev);
0162 }
0163 EXPORT_SYMBOL_GPL(ipu_prg_disable);
0164
0165
0166
0167
0168
0169
0170 static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
0171 {
0172
0173
0174
0175
0176
0177 switch (ipu_chan) {
0178 case IPUV3_CHANNEL_MEM_BG_SYNC:
0179 return 0;
0180 case IPUV3_CHANNEL_MEM_FG_SYNC:
0181 return 1;
0182 case IPUV3_CHANNEL_MEM_DC_SYNC:
0183 return 2;
0184 default:
0185 return -EINVAL;
0186 }
0187 }
0188
0189 static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
0190 {
0191 int i, ret;
0192
0193
0194 if (prg_chan == 0) {
0195 ret = ipu_pre_get(prg->pres[0]);
0196 if (ret)
0197 goto fail;
0198 prg->chan[prg_chan].used_pre = 0;
0199 return 0;
0200 }
0201
0202 for (i = 1; i < 3; i++) {
0203 ret = ipu_pre_get(prg->pres[i]);
0204 if (!ret) {
0205 u32 val, mux;
0206 int shift;
0207
0208 prg->chan[prg_chan].used_pre = i;
0209
0210
0211 shift = (i == 1) ? 12 : 14;
0212 mux = (prg->id << 1) | (prg_chan - 1);
0213 regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
0214 0x3 << shift, mux << shift);
0215
0216
0217 shift = (i == 1) ? 14 : 12;
0218 regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
0219 if (((val >> shift) & 0x3) == mux) {
0220 regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
0221 0x3 << shift,
0222 (mux ^ 0x1) << shift);
0223 }
0224
0225 return 0;
0226 }
0227 }
0228
0229 fail:
0230 dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
0231 return ret;
0232 }
0233
0234 static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
0235 {
0236 struct ipu_prg_channel *chan = &prg->chan[prg_chan];
0237
0238 ipu_pre_put(prg->pres[chan->used_pre]);
0239 chan->used_pre = -1;
0240 }
0241
0242 void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
0243 {
0244 int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
0245 struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
0246 struct ipu_prg_channel *chan;
0247 u32 val;
0248
0249 if (prg_chan < 0)
0250 return;
0251
0252 chan = &prg->chan[prg_chan];
0253 if (!chan->enabled)
0254 return;
0255
0256 pm_runtime_get_sync(prg->dev);
0257
0258 val = readl(prg->regs + IPU_PRG_CTL);
0259 val |= IPU_PRG_CTL_BYPASS(prg_chan);
0260 writel(val, prg->regs + IPU_PRG_CTL);
0261
0262 val = IPU_PRG_REG_UPDATE_REG_UPDATE;
0263 writel(val, prg->regs + IPU_PRG_REG_UPDATE);
0264
0265 pm_runtime_put(prg->dev);
0266
0267 ipu_prg_put_pre(prg, prg_chan);
0268
0269 chan->enabled = false;
0270 }
0271 EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
0272
0273 int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
0274 unsigned int axi_id, unsigned int width,
0275 unsigned int height, unsigned int stride,
0276 u32 format, uint64_t modifier, unsigned long *eba)
0277 {
0278 int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
0279 struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
0280 struct ipu_prg_channel *chan;
0281 u32 val;
0282 int ret;
0283
0284 if (prg_chan < 0)
0285 return prg_chan;
0286
0287 chan = &prg->chan[prg_chan];
0288
0289 if (chan->enabled) {
0290 ipu_pre_update(prg->pres[chan->used_pre], *eba);
0291 return 0;
0292 }
0293
0294 ret = ipu_prg_get_pre(prg, prg_chan);
0295 if (ret)
0296 return ret;
0297
0298 ipu_pre_configure(prg->pres[chan->used_pre],
0299 width, height, stride, format, modifier, *eba);
0300
0301
0302 pm_runtime_get_sync(prg->dev);
0303
0304 val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
0305 writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
0306
0307 val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
0308 IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
0309 ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
0310 IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
0311 writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
0312
0313 val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
0314 *eba = val;
0315 writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
0316
0317 val = readl(prg->regs + IPU_PRG_CTL);
0318
0319 val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
0320 IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
0321 val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
0322
0323 val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
0324 writel(val, prg->regs + IPU_PRG_CTL);
0325
0326 val = IPU_PRG_REG_UPDATE_REG_UPDATE;
0327 writel(val, prg->regs + IPU_PRG_REG_UPDATE);
0328
0329
0330 readl_poll_timeout(prg->regs + IPU_PRG_STATUS, val,
0331 (val & IPU_PRG_STATUS_BUFFER0_READY(prg_chan)) &&
0332 (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
0333 5, 1000);
0334
0335 pm_runtime_put(prg->dev);
0336
0337 chan->enabled = true;
0338 return 0;
0339 }
0340 EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
0341
0342 bool ipu_prg_channel_configure_pending(struct ipuv3_channel *ipu_chan)
0343 {
0344 int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
0345 struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
0346 struct ipu_prg_channel *chan;
0347
0348 if (prg_chan < 0)
0349 return false;
0350
0351 chan = &prg->chan[prg_chan];
0352 WARN_ON(!chan->enabled);
0353
0354 return ipu_pre_update_pending(prg->pres[chan->used_pre]);
0355 }
0356 EXPORT_SYMBOL_GPL(ipu_prg_channel_configure_pending);
0357
0358 static int ipu_prg_probe(struct platform_device *pdev)
0359 {
0360 struct device *dev = &pdev->dev;
0361 struct resource *res;
0362 struct ipu_prg *prg;
0363 u32 val;
0364 int i, ret;
0365
0366 prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
0367 if (!prg)
0368 return -ENOMEM;
0369
0370 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0371 prg->regs = devm_ioremap_resource(&pdev->dev, res);
0372 if (IS_ERR(prg->regs))
0373 return PTR_ERR(prg->regs);
0374
0375
0376 prg->clk_ipg = devm_clk_get(dev, "ipg");
0377 if (IS_ERR(prg->clk_ipg))
0378 return PTR_ERR(prg->clk_ipg);
0379
0380 prg->clk_axi = devm_clk_get(dev, "axi");
0381 if (IS_ERR(prg->clk_axi))
0382 return PTR_ERR(prg->clk_axi);
0383
0384 prg->iomuxc_gpr =
0385 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
0386 if (IS_ERR(prg->iomuxc_gpr))
0387 return PTR_ERR(prg->iomuxc_gpr);
0388
0389 for (i = 0; i < 3; i++) {
0390 prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
0391 if (!prg->pres[i])
0392 return -EPROBE_DEFER;
0393 }
0394
0395 ret = clk_prepare_enable(prg->clk_ipg);
0396 if (ret)
0397 return ret;
0398
0399 ret = clk_prepare_enable(prg->clk_axi);
0400 if (ret) {
0401 clk_disable_unprepare(prg->clk_ipg);
0402 return ret;
0403 }
0404
0405
0406 val = readl(prg->regs + IPU_PRG_CTL);
0407 val |= IPU_PRG_CTL_SHADOW_EN;
0408 writel(val, prg->regs + IPU_PRG_CTL);
0409
0410
0411 writel(0xffffffff, prg->regs + IPU_PRG_THD);
0412
0413 pm_runtime_set_active(dev);
0414 pm_runtime_enable(dev);
0415
0416 prg->dev = dev;
0417 platform_set_drvdata(pdev, prg);
0418 mutex_lock(&ipu_prg_list_mutex);
0419 list_add(&prg->list, &ipu_prg_list);
0420 mutex_unlock(&ipu_prg_list_mutex);
0421
0422 return 0;
0423 }
0424
0425 static int ipu_prg_remove(struct platform_device *pdev)
0426 {
0427 struct ipu_prg *prg = platform_get_drvdata(pdev);
0428
0429 mutex_lock(&ipu_prg_list_mutex);
0430 list_del(&prg->list);
0431 mutex_unlock(&ipu_prg_list_mutex);
0432
0433 return 0;
0434 }
0435
0436 #ifdef CONFIG_PM
0437 static int prg_suspend(struct device *dev)
0438 {
0439 struct ipu_prg *prg = dev_get_drvdata(dev);
0440
0441 clk_disable_unprepare(prg->clk_axi);
0442 clk_disable_unprepare(prg->clk_ipg);
0443
0444 return 0;
0445 }
0446
0447 static int prg_resume(struct device *dev)
0448 {
0449 struct ipu_prg *prg = dev_get_drvdata(dev);
0450 int ret;
0451
0452 ret = clk_prepare_enable(prg->clk_ipg);
0453 if (ret)
0454 return ret;
0455
0456 ret = clk_prepare_enable(prg->clk_axi);
0457 if (ret) {
0458 clk_disable_unprepare(prg->clk_ipg);
0459 return ret;
0460 }
0461
0462 return 0;
0463 }
0464 #endif
0465
0466 static const struct dev_pm_ops prg_pm_ops = {
0467 SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
0468 };
0469
0470 static const struct of_device_id ipu_prg_dt_ids[] = {
0471 { .compatible = "fsl,imx6qp-prg", },
0472 { },
0473 };
0474
0475 struct platform_driver ipu_prg_drv = {
0476 .probe = ipu_prg_probe,
0477 .remove = ipu_prg_remove,
0478 .driver = {
0479 .name = "imx-ipu-prg",
0480 .pm = &prg_pm_ops,
0481 .of_match_table = ipu_prg_dt_ids,
0482 },
0483 };