Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TI da8xx master peripheral priority driver
0004  *
0005  * Copyright (C) 2016 BayLibre SAS
0006  *
0007  * Author:
0008  *   Bartosz Golaszewski <bgolaszewski@baylibre.com>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/io.h>
0015 #include <linux/regmap.h>
0016 
0017 /*
0018  * REVISIT: Linux doesn't have a good framework for the kind of performance
0019  * knobs this driver controls. We can't use device tree properties as it deals
0020  * with hardware configuration rather than description. We also don't want to
0021  * commit to maintaining some random sysfs attributes.
0022  *
0023  * For now we just hardcode the register values for the boards that need
0024  * some changes (as is the case for the LCD controller on da850-lcdk - the
0025  * first board we support here). When linux gets an appropriate framework,
0026  * we'll easily convert the driver to it.
0027  */
0028 
0029 #define DA8XX_MSTPRI0_OFFSET        0
0030 #define DA8XX_MSTPRI1_OFFSET        4
0031 #define DA8XX_MSTPRI2_OFFSET        8
0032 
0033 enum {
0034     DA8XX_MSTPRI_ARM_I = 0,
0035     DA8XX_MSTPRI_ARM_D,
0036     DA8XX_MSTPRI_UPP,
0037     DA8XX_MSTPRI_SATA,
0038     DA8XX_MSTPRI_PRU0,
0039     DA8XX_MSTPRI_PRU1,
0040     DA8XX_MSTPRI_EDMA30TC0,
0041     DA8XX_MSTPRI_EDMA30TC1,
0042     DA8XX_MSTPRI_EDMA31TC0,
0043     DA8XX_MSTPRI_VPIF_DMA_0,
0044     DA8XX_MSTPRI_VPIF_DMA_1,
0045     DA8XX_MSTPRI_EMAC,
0046     DA8XX_MSTPRI_USB0CFG,
0047     DA8XX_MSTPRI_USB0CDMA,
0048     DA8XX_MSTPRI_UHPI,
0049     DA8XX_MSTPRI_USB1,
0050     DA8XX_MSTPRI_LCDC,
0051 };
0052 
0053 struct da8xx_mstpri_descr {
0054     int reg;
0055     int shift;
0056     int mask;
0057 };
0058 
0059 static const struct da8xx_mstpri_descr da8xx_mstpri_priority_list[] = {
0060     [DA8XX_MSTPRI_ARM_I] = {
0061         .reg = DA8XX_MSTPRI0_OFFSET,
0062         .shift = 0,
0063         .mask = 0x0000000f,
0064     },
0065     [DA8XX_MSTPRI_ARM_D] = {
0066         .reg = DA8XX_MSTPRI0_OFFSET,
0067         .shift = 4,
0068         .mask = 0x000000f0,
0069     },
0070     [DA8XX_MSTPRI_UPP] = {
0071         .reg = DA8XX_MSTPRI0_OFFSET,
0072         .shift = 16,
0073         .mask = 0x000f0000,
0074     },
0075     [DA8XX_MSTPRI_SATA] = {
0076         .reg = DA8XX_MSTPRI0_OFFSET,
0077         .shift = 20,
0078         .mask = 0x00f00000,
0079     },
0080     [DA8XX_MSTPRI_PRU0] = {
0081         .reg = DA8XX_MSTPRI1_OFFSET,
0082         .shift = 0,
0083         .mask = 0x0000000f,
0084     },
0085     [DA8XX_MSTPRI_PRU1] = {
0086         .reg = DA8XX_MSTPRI1_OFFSET,
0087         .shift = 4,
0088         .mask = 0x000000f0,
0089     },
0090     [DA8XX_MSTPRI_EDMA30TC0] = {
0091         .reg = DA8XX_MSTPRI1_OFFSET,
0092         .shift = 8,
0093         .mask = 0x00000f00,
0094     },
0095     [DA8XX_MSTPRI_EDMA30TC1] = {
0096         .reg = DA8XX_MSTPRI1_OFFSET,
0097         .shift = 12,
0098         .mask = 0x0000f000,
0099     },
0100     [DA8XX_MSTPRI_EDMA31TC0] = {
0101         .reg = DA8XX_MSTPRI1_OFFSET,
0102         .shift = 16,
0103         .mask = 0x000f0000,
0104     },
0105     [DA8XX_MSTPRI_VPIF_DMA_0] = {
0106         .reg = DA8XX_MSTPRI1_OFFSET,
0107         .shift = 24,
0108         .mask = 0x0f000000,
0109     },
0110     [DA8XX_MSTPRI_VPIF_DMA_1] = {
0111         .reg = DA8XX_MSTPRI1_OFFSET,
0112         .shift = 28,
0113         .mask = 0xf0000000,
0114     },
0115     [DA8XX_MSTPRI_EMAC] = {
0116         .reg = DA8XX_MSTPRI2_OFFSET,
0117         .shift = 0,
0118         .mask = 0x0000000f,
0119     },
0120     [DA8XX_MSTPRI_USB0CFG] = {
0121         .reg = DA8XX_MSTPRI2_OFFSET,
0122         .shift = 8,
0123         .mask = 0x00000f00,
0124     },
0125     [DA8XX_MSTPRI_USB0CDMA] = {
0126         .reg = DA8XX_MSTPRI2_OFFSET,
0127         .shift = 12,
0128         .mask = 0x0000f000,
0129     },
0130     [DA8XX_MSTPRI_UHPI] = {
0131         .reg = DA8XX_MSTPRI2_OFFSET,
0132         .shift = 20,
0133         .mask = 0x00f00000,
0134     },
0135     [DA8XX_MSTPRI_USB1] = {
0136         .reg = DA8XX_MSTPRI2_OFFSET,
0137         .shift = 24,
0138         .mask = 0x0f000000,
0139     },
0140     [DA8XX_MSTPRI_LCDC] = {
0141         .reg = DA8XX_MSTPRI2_OFFSET,
0142         .shift = 28,
0143         .mask = 0xf0000000,
0144     },
0145 };
0146 
0147 struct da8xx_mstpri_priority {
0148     int which;
0149     u32 val;
0150 };
0151 
0152 struct da8xx_mstpri_board_priorities {
0153     const char *board;
0154     const struct da8xx_mstpri_priority *priorities;
0155     size_t numprio;
0156 };
0157 
0158 /*
0159  * Default memory settings of da850 do not meet the throughput/latency
0160  * requirements of tilcdc. This results in the image displayed being
0161  * incorrect and the following warning being displayed by the LCDC
0162  * drm driver:
0163  *
0164  *   tilcdc da8xx_lcdc.0: tilcdc_crtc_irq(0x00000020): FIFO underfow
0165  */
0166 static const struct da8xx_mstpri_priority da850_lcdk_priorities[] = {
0167     {
0168         .which = DA8XX_MSTPRI_LCDC,
0169         .val = 0,
0170     },
0171     {
0172         .which = DA8XX_MSTPRI_EDMA30TC1,
0173         .val = 0,
0174     },
0175     {
0176         .which = DA8XX_MSTPRI_EDMA30TC0,
0177         .val = 1,
0178     },
0179 };
0180 
0181 static const struct da8xx_mstpri_board_priorities da8xx_mstpri_board_confs[] = {
0182     {
0183         .board = "ti,da850-lcdk",
0184         .priorities = da850_lcdk_priorities,
0185         .numprio = ARRAY_SIZE(da850_lcdk_priorities),
0186     },
0187 };
0188 
0189 static const struct da8xx_mstpri_board_priorities *
0190 da8xx_mstpri_get_board_prio(void)
0191 {
0192     const struct da8xx_mstpri_board_priorities *board_prio;
0193     int i;
0194 
0195     for (i = 0; i < ARRAY_SIZE(da8xx_mstpri_board_confs); i++) {
0196         board_prio = &da8xx_mstpri_board_confs[i];
0197 
0198         if (of_machine_is_compatible(board_prio->board))
0199             return board_prio;
0200     }
0201 
0202     return NULL;
0203 }
0204 
0205 static int da8xx_mstpri_probe(struct platform_device *pdev)
0206 {
0207     const struct da8xx_mstpri_board_priorities *prio_list;
0208     const struct da8xx_mstpri_descr *prio_descr;
0209     const struct da8xx_mstpri_priority *prio;
0210     struct device *dev = &pdev->dev;
0211     struct resource *res;
0212     void __iomem *mstpri;
0213     u32 reg;
0214     int i;
0215 
0216     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0217     mstpri = devm_ioremap_resource(dev, res);
0218     if (IS_ERR(mstpri)) {
0219         dev_err(dev, "unable to map MSTPRI registers\n");
0220         return PTR_ERR(mstpri);
0221     }
0222 
0223     prio_list = da8xx_mstpri_get_board_prio();
0224     if (!prio_list) {
0225         dev_err(dev, "no master priorities defined for this board\n");
0226         return -EINVAL;
0227     }
0228 
0229     for (i = 0; i < prio_list->numprio; i++) {
0230         prio = &prio_list->priorities[i];
0231         prio_descr = &da8xx_mstpri_priority_list[prio->which];
0232 
0233         if (prio_descr->reg + sizeof(u32) > resource_size(res)) {
0234             dev_warn(dev, "register offset out of range\n");
0235             continue;
0236         }
0237 
0238         reg = readl(mstpri + prio_descr->reg);
0239         reg &= ~prio_descr->mask;
0240         reg |= prio->val << prio_descr->shift;
0241 
0242         writel(reg, mstpri + prio_descr->reg);
0243     }
0244 
0245     return 0;
0246 }
0247 
0248 static const struct of_device_id da8xx_mstpri_of_match[] = {
0249     { .compatible = "ti,da850-mstpri", },
0250     { },
0251 };
0252 
0253 static struct platform_driver da8xx_mstpri_driver = {
0254     .probe = da8xx_mstpri_probe,
0255     .driver = {
0256         .name = "da8xx-mstpri",
0257         .of_match_table = da8xx_mstpri_of_match,
0258     },
0259 };
0260 module_platform_driver(da8xx_mstpri_driver);
0261 
0262 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
0263 MODULE_DESCRIPTION("TI da8xx master peripheral priority driver");
0264 MODULE_LICENSE("GPL v2");