0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
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
0327 .max_register = SUNXI_SRAM_EMAC_CLOCK_REG + 4,
0328
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");