Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Allwinner SoCs SRAM Controller Driver
0003  *
0004  * Copyright (C) 2015 Maxime Ripard
0005  *
0006  * Author: Maxime Ripard <maxime.ripard@free-electrons.com>
0007  *
0008  * This file is licensed under the terms of the GNU General Public
0009  * License version 2.  This program is licensed "as is" without any
0010  * warranty of any kind, whether express or implied.
0011  */
0012 
0013 #include <linux/debugfs.h>
0014 #include <linux/io.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/of_address.h>
0018 #include <linux/of_device.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regmap.h>
0021 
0022 #include <linux/soc/sunxi/sunxi_sram.h>
0023 
0024 struct sunxi_sram_func {
0025     char    *func;
0026     u8  val;
0027     u32 reg_val;
0028 };
0029 
0030 struct sunxi_sram_data {
0031     char            *name;
0032     u8          reg;
0033     u8          offset;
0034     u8          width;
0035     struct sunxi_sram_func  *func;
0036     struct list_head    list;
0037 };
0038 
0039 struct sunxi_sram_desc {
0040     struct sunxi_sram_data  data;
0041     bool            claimed;
0042 };
0043 
0044 #define SUNXI_SRAM_MAP(_reg_val, _val, _func)           \
0045     {                           \
0046         .func = _func,                  \
0047         .val = _val,                    \
0048         .reg_val = _reg_val,                \
0049     }
0050 
0051 #define SUNXI_SRAM_DATA(_name, _reg, _off, _width, ...)     \
0052     {                           \
0053         .name = _name,                  \
0054         .reg = _reg,                    \
0055         .offset = _off,                 \
0056         .width = _width,                \
0057         .func = (struct sunxi_sram_func[]){     \
0058             __VA_ARGS__, { } },         \
0059     }
0060 
0061 static struct sunxi_sram_desc sun4i_a10_sram_a3_a4 = {
0062     .data   = SUNXI_SRAM_DATA("A3-A4", 0x4, 0x4, 2,
0063                   SUNXI_SRAM_MAP(0, 0, "cpu"),
0064                   SUNXI_SRAM_MAP(1, 1, "emac")),
0065 };
0066 
0067 static struct sunxi_sram_desc sun4i_a10_sram_c1 = {
0068     .data   = SUNXI_SRAM_DATA("C1", 0x0, 0x0, 31,
0069                   SUNXI_SRAM_MAP(0, 0, "cpu"),
0070                   SUNXI_SRAM_MAP(0x7fffffff, 1, "ve")),
0071 };
0072 
0073 static struct sunxi_sram_desc sun4i_a10_sram_d = {
0074     .data   = SUNXI_SRAM_DATA("D", 0x4, 0x0, 1,
0075                   SUNXI_SRAM_MAP(0, 0, "cpu"),
0076                   SUNXI_SRAM_MAP(1, 1, "usb-otg")),
0077 };
0078 
0079 static struct sunxi_sram_desc sun50i_a64_sram_c = {
0080     .data   = SUNXI_SRAM_DATA("C", 0x4, 24, 1,
0081                   SUNXI_SRAM_MAP(1, 0, "cpu"),
0082                   SUNXI_SRAM_MAP(0, 1, "de2")),
0083 };
0084 
0085 static const struct of_device_id sunxi_sram_dt_ids[] = {
0086     {
0087         .compatible = "allwinner,sun4i-a10-sram-a3-a4",
0088         .data       = &sun4i_a10_sram_a3_a4.data,
0089     },
0090     {
0091         .compatible = "allwinner,sun4i-a10-sram-c1",
0092         .data       = &sun4i_a10_sram_c1.data,
0093     },
0094     {
0095         .compatible = "allwinner,sun4i-a10-sram-d",
0096         .data       = &sun4i_a10_sram_d.data,
0097     },
0098     {
0099         .compatible = "allwinner,sun50i-a64-sram-c",
0100         .data       = &sun50i_a64_sram_c.data,
0101     },
0102     {}
0103 };
0104 
0105 static struct device *sram_dev;
0106 static LIST_HEAD(claimed_sram);
0107 static DEFINE_SPINLOCK(sram_lock);
0108 static void __iomem *base;
0109 
0110 static int sunxi_sram_show(struct seq_file *s, void *data)
0111 {
0112     struct device_node *sram_node, *section_node;
0113     const struct sunxi_sram_data *sram_data;
0114     const struct of_device_id *match;
0115     struct sunxi_sram_func *func;
0116     const __be32 *sram_addr_p, *section_addr_p;
0117     u32 val;
0118 
0119     seq_puts(s, "Allwinner sunXi SRAM\n");
0120     seq_puts(s, "--------------------\n\n");
0121 
0122     for_each_child_of_node(sram_dev->of_node, sram_node) {
0123         sram_addr_p = of_get_address(sram_node, 0, NULL, NULL);
0124 
0125         seq_printf(s, "sram@%08x\n",
0126                be32_to_cpu(*sram_addr_p));
0127 
0128         for_each_child_of_node(sram_node, section_node) {
0129             match = of_match_node(sunxi_sram_dt_ids, section_node);
0130             if (!match)
0131                 continue;
0132             sram_data = match->data;
0133 
0134             section_addr_p = of_get_address(section_node, 0,
0135                             NULL, NULL);
0136 
0137             seq_printf(s, "\tsection@%04x\t(%s)\n",
0138                    be32_to_cpu(*section_addr_p),
0139                    sram_data->name);
0140 
0141             val = readl(base + sram_data->reg);
0142             val >>= sram_data->offset;
0143             val &= GENMASK(sram_data->width - 1, 0);
0144 
0145             for (func = sram_data->func; func->func; func++) {
0146                 seq_printf(s, "\t\t%s%c\n", func->func,
0147                        func->reg_val == val ?
0148                        '*' : ' ');
0149             }
0150         }
0151 
0152         seq_puts(s, "\n");
0153     }
0154 
0155     return 0;
0156 }
0157 
0158 DEFINE_SHOW_ATTRIBUTE(sunxi_sram);
0159 
0160 static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data)
0161 {
0162     return container_of(data, struct sunxi_sram_desc, data);
0163 }
0164 
0165 static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node,
0166                              unsigned int *reg_value)
0167 {
0168     const struct of_device_id *match;
0169     const struct sunxi_sram_data *data;
0170     struct sunxi_sram_func *func;
0171     struct of_phandle_args args;
0172     u8 val;
0173     int ret;
0174 
0175     ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0,
0176                            &args);
0177     if (ret)
0178         return ERR_PTR(ret);
0179 
0180     if (!of_device_is_available(args.np)) {
0181         ret = -EBUSY;
0182         goto err;
0183     }
0184 
0185     val = args.args[0];
0186 
0187     match = of_match_node(sunxi_sram_dt_ids, args.np);
0188     if (!match) {
0189         ret = -EINVAL;
0190         goto err;
0191     }
0192 
0193     data = match->data;
0194     if (!data) {
0195         ret = -EINVAL;
0196         goto err;
0197     }
0198 
0199     for (func = data->func; func->func; func++) {
0200         if (val == func->val) {
0201             if (reg_value)
0202                 *reg_value = func->reg_val;
0203 
0204             break;
0205         }
0206     }
0207 
0208     if (!func->func) {
0209         ret = -EINVAL;
0210         goto err;
0211     }
0212 
0213     of_node_put(args.np);
0214     return match->data;
0215 
0216 err:
0217     of_node_put(args.np);
0218     return ERR_PTR(ret);
0219 }
0220 
0221 int sunxi_sram_claim(struct device *dev)
0222 {
0223     const struct sunxi_sram_data *sram_data;
0224     struct sunxi_sram_desc *sram_desc;
0225     unsigned int device;
0226     u32 val, mask;
0227 
0228     if (IS_ERR(base))
0229         return PTR_ERR(base);
0230 
0231     if (!base)
0232         return -EPROBE_DEFER;
0233 
0234     if (!dev || !dev->of_node)
0235         return -EINVAL;
0236 
0237     sram_data = sunxi_sram_of_parse(dev->of_node, &device);
0238     if (IS_ERR(sram_data))
0239         return PTR_ERR(sram_data);
0240 
0241     sram_desc = to_sram_desc(sram_data);
0242 
0243     spin_lock(&sram_lock);
0244 
0245     if (sram_desc->claimed) {
0246         spin_unlock(&sram_lock);
0247         return -EBUSY;
0248     }
0249 
0250     mask = GENMASK(sram_data->offset + sram_data->width - 1,
0251                sram_data->offset);
0252     val = readl(base + sram_data->reg);
0253     val &= ~mask;
0254     writel(val | ((device << sram_data->offset) & mask),
0255            base + sram_data->reg);
0256 
0257     sram_desc->claimed = true;
0258     spin_unlock(&sram_lock);
0259 
0260     return 0;
0261 }
0262 EXPORT_SYMBOL(sunxi_sram_claim);
0263 
0264 int sunxi_sram_release(struct device *dev)
0265 {
0266     const struct sunxi_sram_data *sram_data;
0267     struct sunxi_sram_desc *sram_desc;
0268 
0269     if (!dev || !dev->of_node)
0270         return -EINVAL;
0271 
0272     sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
0273     if (IS_ERR(sram_data))
0274         return -EINVAL;
0275 
0276     sram_desc = to_sram_desc(sram_data);
0277 
0278     spin_lock(&sram_lock);
0279     sram_desc->claimed = false;
0280     spin_unlock(&sram_lock);
0281 
0282     return 0;
0283 }
0284 EXPORT_SYMBOL(sunxi_sram_release);
0285 
0286 struct sunxi_sramc_variant {
0287     int num_emac_clocks;
0288 };
0289 
0290 static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
0291     /* Nothing special */
0292 };
0293 
0294 static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = {
0295     .num_emac_clocks = 1,
0296 };
0297 
0298 static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
0299     .num_emac_clocks = 1,
0300 };
0301 
0302 static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = {
0303     .num_emac_clocks = 2,
0304 };
0305 
0306 #define SUNXI_SRAM_EMAC_CLOCK_REG   0x30
0307 static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
0308                          unsigned int reg)
0309 {
0310     const struct sunxi_sramc_variant *variant;
0311 
0312     variant = of_device_get_match_data(dev);
0313 
0314     if (reg < SUNXI_SRAM_EMAC_CLOCK_REG)
0315         return false;
0316     if (reg > SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
0317         return false;
0318 
0319     return true;
0320 }
0321 
0322 static struct regmap_config sunxi_sram_emac_clock_regmap = {
0323     .reg_bits       = 32,
0324     .val_bits       = 32,
0325     .reg_stride     = 4,
0326     /* last defined register */
0327     .max_register   = SUNXI_SRAM_EMAC_CLOCK_REG + 4,
0328     /* other devices have no business accessing other registers */
0329     .readable_reg   = sunxi_sram_regmap_accessible_reg,
0330     .writeable_reg  = sunxi_sram_regmap_accessible_reg,
0331 };
0332 
0333 static int __init sunxi_sram_probe(struct platform_device *pdev)
0334 {
0335     struct regmap *emac_clock;
0336     const struct sunxi_sramc_variant *variant;
0337     struct device *dev = &pdev->dev;
0338 
0339     sram_dev = &pdev->dev;
0340 
0341     variant = of_device_get_match_data(&pdev->dev);
0342     if (!variant)
0343         return -EINVAL;
0344 
0345     base = devm_platform_ioremap_resource(pdev, 0);
0346     if (IS_ERR(base))
0347         return PTR_ERR(base);
0348 
0349     if (variant->num_emac_clocks > 0) {
0350         emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
0351                            &sunxi_sram_emac_clock_regmap);
0352 
0353         if (IS_ERR(emac_clock))
0354             return PTR_ERR(emac_clock);
0355     }
0356 
0357     of_platform_populate(dev->of_node, NULL, NULL, dev);
0358 
0359     debugfs_create_file("sram", 0444, NULL, NULL, &sunxi_sram_fops);
0360 
0361     return 0;
0362 }
0363 
0364 static const struct of_device_id sunxi_sram_dt_match[] = {
0365     {
0366         .compatible = "allwinner,sun4i-a10-sram-controller",
0367         .data = &sun4i_a10_sramc_variant,
0368     },
0369     {
0370         .compatible = "allwinner,sun4i-a10-system-control",
0371         .data = &sun4i_a10_sramc_variant,
0372     },
0373     {
0374         .compatible = "allwinner,sun5i-a13-system-control",
0375         .data = &sun4i_a10_sramc_variant,
0376     },
0377     {
0378         .compatible = "allwinner,sun8i-a23-system-control",
0379         .data = &sun4i_a10_sramc_variant,
0380     },
0381     {
0382         .compatible = "allwinner,sun8i-h3-system-control",
0383         .data = &sun8i_h3_sramc_variant,
0384     },
0385     {
0386         .compatible = "allwinner,sun50i-a64-sram-controller",
0387         .data = &sun50i_a64_sramc_variant,
0388     },
0389     {
0390         .compatible = "allwinner,sun50i-a64-system-control",
0391         .data = &sun50i_a64_sramc_variant,
0392     },
0393     {
0394         .compatible = "allwinner,sun50i-h5-system-control",
0395         .data = &sun50i_a64_sramc_variant,
0396     },
0397     {
0398         .compatible = "allwinner,sun50i-h616-system-control",
0399         .data = &sun50i_h616_sramc_variant,
0400     },
0401     { },
0402 };
0403 MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
0404 
0405 static struct platform_driver sunxi_sram_driver = {
0406     .driver = {
0407         .name       = "sunxi-sram",
0408         .of_match_table = sunxi_sram_dt_match,
0409     },
0410 };
0411 builtin_platform_driver_probe(sunxi_sram_driver, sunxi_sram_probe);
0412 
0413 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
0414 MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver");
0415 MODULE_LICENSE("GPL");