GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / memory / samsung / exynos-srom.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 //            http://www.samsung.com/
5 //
6 // EXYNOS - SROM Controller support
7 // Author: Pankaj Dubey <pankaj.dubey@samsung.com>
8
9 #include <linux/io.h>
10 #include <linux/init.h>
11 #include <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/of_platform.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16
17 #include "exynos-srom.h"
18
19 static const unsigned long exynos_srom_offsets[] = {
20         /* SROM side */
21         EXYNOS_SROM_BW,
22         EXYNOS_SROM_BC0,
23         EXYNOS_SROM_BC1,
24         EXYNOS_SROM_BC2,
25         EXYNOS_SROM_BC3,
26 };
27
28 /**
29  * struct exynos_srom_reg_dump: register dump of SROM Controller registers.
30  * @offset: srom register offset from the controller base address.
31  * @value: the value of register under the offset.
32  */
33 struct exynos_srom_reg_dump {
34         u32     offset;
35         u32     value;
36 };
37
38 /**
39  * struct exynos_srom: platform data for exynos srom controller driver.
40  * @dev: platform device pointer
41  * @reg_base: srom base address
42  * @reg_offset: exynos_srom_reg_dump pointer to hold offset and its value.
43  */
44 struct exynos_srom {
45         struct device *dev;
46         void __iomem *reg_base;
47         struct exynos_srom_reg_dump *reg_offset;
48 };
49
50 static struct exynos_srom_reg_dump *exynos_srom_alloc_reg_dump(
51                 const unsigned long *rdump,
52                 unsigned long nr_rdump)
53 {
54         struct exynos_srom_reg_dump *rd;
55         unsigned int i;
56
57         rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL);
58         if (!rd)
59                 return NULL;
60
61         for (i = 0; i < nr_rdump; ++i)
62                 rd[i].offset = rdump[i];
63
64         return rd;
65 }
66
67 static int exynos_srom_configure_bank(struct exynos_srom *srom,
68                                       struct device_node *np)
69 {
70         u32 bank, width, pmc = 0;
71         u32 timing[6];
72         u32 cs, bw;
73
74         if (of_property_read_u32(np, "reg", &bank))
75                 return -EINVAL;
76         if (of_property_read_u32(np, "reg-io-width", &width))
77                 width = 1;
78         if (of_property_read_bool(np, "samsung,srom-page-mode"))
79                 pmc = 1 << EXYNOS_SROM_BCX__PMC__SHIFT;
80         if (of_property_read_u32_array(np, "samsung,srom-timing", timing,
81                                        ARRAY_SIZE(timing)))
82                 return -EINVAL;
83
84         bank *= 4; /* Convert bank into shift/offset */
85
86         cs = 1 << EXYNOS_SROM_BW__BYTEENABLE__SHIFT;
87         if (width == 2)
88                 cs |= 1 << EXYNOS_SROM_BW__DATAWIDTH__SHIFT;
89
90         bw = readl_relaxed(srom->reg_base + EXYNOS_SROM_BW);
91         bw = (bw & ~(EXYNOS_SROM_BW__CS_MASK << bank)) | (cs << bank);
92         writel_relaxed(bw, srom->reg_base + EXYNOS_SROM_BW);
93
94         writel_relaxed(pmc | (timing[0] << EXYNOS_SROM_BCX__TACP__SHIFT) |
95                        (timing[1] << EXYNOS_SROM_BCX__TCAH__SHIFT) |
96                        (timing[2] << EXYNOS_SROM_BCX__TCOH__SHIFT) |
97                        (timing[3] << EXYNOS_SROM_BCX__TACC__SHIFT) |
98                        (timing[4] << EXYNOS_SROM_BCX__TCOS__SHIFT) |
99                        (timing[5] << EXYNOS_SROM_BCX__TACS__SHIFT),
100                        srom->reg_base + EXYNOS_SROM_BC0 + bank);
101
102         return 0;
103 }
104
105 static int exynos_srom_probe(struct platform_device *pdev)
106 {
107         struct device_node *np, *child;
108         struct exynos_srom *srom;
109         struct device *dev = &pdev->dev;
110         bool bad_bank_config = false;
111
112         np = dev->of_node;
113         if (!np) {
114                 dev_err(&pdev->dev, "could not find device info\n");
115                 return -EINVAL;
116         }
117
118         srom = devm_kzalloc(&pdev->dev,
119                         sizeof(struct exynos_srom), GFP_KERNEL);
120         if (!srom)
121                 return -ENOMEM;
122
123         srom->dev = dev;
124         srom->reg_base = of_iomap(np, 0);
125         if (!srom->reg_base) {
126                 dev_err(&pdev->dev, "iomap of exynos srom controller failed\n");
127                 return -ENOMEM;
128         }
129
130         platform_set_drvdata(pdev, srom);
131
132         srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets,
133                         ARRAY_SIZE(exynos_srom_offsets));
134         if (!srom->reg_offset) {
135                 iounmap(srom->reg_base);
136                 return -ENOMEM;
137         }
138
139         for_each_child_of_node(np, child) {
140                 if (exynos_srom_configure_bank(srom, child)) {
141                         dev_err(dev,
142                                 "Could not decode bank configuration for %s\n",
143                                 child->name);
144                         bad_bank_config = true;
145                 }
146         }
147
148         /*
149          * If any bank failed to configure, we still provide suspend/resume,
150          * but do not probe child devices
151          */
152         if (bad_bank_config)
153                 return 0;
154
155         return of_platform_populate(np, NULL, NULL, dev);
156 }
157
158 #ifdef CONFIG_PM_SLEEP
159 static void exynos_srom_save(void __iomem *base,
160                                     struct exynos_srom_reg_dump *rd,
161                                     unsigned int num_regs)
162 {
163         for (; num_regs > 0; --num_regs, ++rd)
164                 rd->value = readl(base + rd->offset);
165 }
166
167 static void exynos_srom_restore(void __iomem *base,
168                                       const struct exynos_srom_reg_dump *rd,
169                                       unsigned int num_regs)
170 {
171         for (; num_regs > 0; --num_regs, ++rd)
172                 writel(rd->value, base + rd->offset);
173 }
174
175 static int exynos_srom_suspend(struct device *dev)
176 {
177         struct exynos_srom *srom = dev_get_drvdata(dev);
178
179         exynos_srom_save(srom->reg_base, srom->reg_offset,
180                                 ARRAY_SIZE(exynos_srom_offsets));
181         return 0;
182 }
183
184 static int exynos_srom_resume(struct device *dev)
185 {
186         struct exynos_srom *srom = dev_get_drvdata(dev);
187
188         exynos_srom_restore(srom->reg_base, srom->reg_offset,
189                                 ARRAY_SIZE(exynos_srom_offsets));
190         return 0;
191 }
192 #endif
193
194 static const struct of_device_id of_exynos_srom_ids[] = {
195         {
196                 .compatible     = "samsung,exynos4210-srom",
197         },
198         {},
199 };
200
201 static SIMPLE_DEV_PM_OPS(exynos_srom_pm_ops, exynos_srom_suspend, exynos_srom_resume);
202
203 static struct platform_driver exynos_srom_driver = {
204         .probe = exynos_srom_probe,
205         .driver = {
206                 .name = "exynos-srom",
207                 .of_match_table = of_exynos_srom_ids,
208                 .pm = &exynos_srom_pm_ops,
209                 .suppress_bind_attrs = true,
210         },
211 };
212 builtin_platform_driver(exynos_srom_driver);