1477dfdccSXu Yilun // SPDX-License-Identifier: GPL-2.0
2477dfdccSXu Yilun /*
3477dfdccSXu Yilun * DFL device driver for EMIF private feature
4477dfdccSXu Yilun *
5477dfdccSXu Yilun * Copyright (C) 2020 Intel Corporation, Inc.
6477dfdccSXu Yilun *
7477dfdccSXu Yilun */
8477dfdccSXu Yilun #include <linux/bitfield.h>
9477dfdccSXu Yilun #include <linux/dfl.h>
10477dfdccSXu Yilun #include <linux/errno.h>
11477dfdccSXu Yilun #include <linux/io.h>
12477dfdccSXu Yilun #include <linux/iopoll.h>
13477dfdccSXu Yilun #include <linux/io-64-nonatomic-lo-hi.h>
14477dfdccSXu Yilun #include <linux/kernel.h>
15477dfdccSXu Yilun #include <linux/module.h>
16477dfdccSXu Yilun #include <linux/spinlock.h>
17477dfdccSXu Yilun #include <linux/types.h>
18477dfdccSXu Yilun
19477dfdccSXu Yilun #define FME_FEATURE_ID_EMIF 0x9
20477dfdccSXu Yilun
21477dfdccSXu Yilun #define EMIF_STAT 0x8
22477dfdccSXu Yilun #define EMIF_STAT_INIT_DONE_SFT 0
23477dfdccSXu Yilun #define EMIF_STAT_CALC_FAIL_SFT 8
24477dfdccSXu Yilun #define EMIF_STAT_CLEAR_BUSY_SFT 16
25477dfdccSXu Yilun #define EMIF_CTRL 0x10
26477dfdccSXu Yilun #define EMIF_CTRL_CLEAR_EN_SFT 0
27*8e478758SDebarati Biswas #define EMIF_CTRL_CLEAR_EN_MSK GENMASK_ULL(7, 0)
28477dfdccSXu Yilun
29477dfdccSXu Yilun #define EMIF_POLL_INVL 10000 /* us */
30477dfdccSXu Yilun #define EMIF_POLL_TIMEOUT 5000000 /* us */
31477dfdccSXu Yilun
32*8e478758SDebarati Biswas /*
33*8e478758SDebarati Biswas * The Capability Register replaces the Control Register (at the same
34*8e478758SDebarati Biswas * offset) for EMIF feature revisions > 0. The bitmask that indicates
35*8e478758SDebarati Biswas * the presence of memory channels exists in both the Capability Register
36*8e478758SDebarati Biswas * and Control Register definitions. These can be thought of as a C union.
37*8e478758SDebarati Biswas * The Capability Register definitions are used to check for the existence
38*8e478758SDebarati Biswas * of a memory channel, and the Control Register definitions are used for
39*8e478758SDebarati Biswas * managing the memory-clear functionality in revision 0.
40*8e478758SDebarati Biswas */
41*8e478758SDebarati Biswas #define EMIF_CAPABILITY_BASE 0x10
42*8e478758SDebarati Biswas #define EMIF_CAPABILITY_CHN_MSK_V0 GENMASK_ULL(3, 0)
43*8e478758SDebarati Biswas #define EMIF_CAPABILITY_CHN_MSK GENMASK_ULL(7, 0)
44*8e478758SDebarati Biswas
45477dfdccSXu Yilun struct dfl_emif {
46477dfdccSXu Yilun struct device *dev;
47477dfdccSXu Yilun void __iomem *base;
48477dfdccSXu Yilun spinlock_t lock; /* Serialises access to EMIF_CTRL reg */
49477dfdccSXu Yilun };
50477dfdccSXu Yilun
51477dfdccSXu Yilun struct emif_attr {
52477dfdccSXu Yilun struct device_attribute attr;
53477dfdccSXu Yilun u32 shift;
54477dfdccSXu Yilun u32 index;
55477dfdccSXu Yilun };
56477dfdccSXu Yilun
57477dfdccSXu Yilun #define to_emif_attr(dev_attr) \
58477dfdccSXu Yilun container_of(dev_attr, struct emif_attr, attr)
59477dfdccSXu Yilun
emif_state_show(struct device * dev,struct device_attribute * attr,char * buf)60477dfdccSXu Yilun static ssize_t emif_state_show(struct device *dev,
61477dfdccSXu Yilun struct device_attribute *attr, char *buf)
62477dfdccSXu Yilun {
63477dfdccSXu Yilun struct emif_attr *eattr = to_emif_attr(attr);
64477dfdccSXu Yilun struct dfl_emif *de = dev_get_drvdata(dev);
65477dfdccSXu Yilun u64 val;
66477dfdccSXu Yilun
67477dfdccSXu Yilun val = readq(de->base + EMIF_STAT);
68477dfdccSXu Yilun
69477dfdccSXu Yilun return sysfs_emit(buf, "%u\n",
70477dfdccSXu Yilun !!(val & BIT_ULL(eattr->shift + eattr->index)));
71477dfdccSXu Yilun }
72477dfdccSXu Yilun
emif_clear_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)73477dfdccSXu Yilun static ssize_t emif_clear_store(struct device *dev,
74477dfdccSXu Yilun struct device_attribute *attr,
75477dfdccSXu Yilun const char *buf, size_t count)
76477dfdccSXu Yilun {
77477dfdccSXu Yilun struct emif_attr *eattr = to_emif_attr(attr);
78477dfdccSXu Yilun struct dfl_emif *de = dev_get_drvdata(dev);
79477dfdccSXu Yilun u64 clear_busy_msk, clear_en_msk, val;
80477dfdccSXu Yilun void __iomem *base = de->base;
81477dfdccSXu Yilun
82477dfdccSXu Yilun if (!sysfs_streq(buf, "1"))
83477dfdccSXu Yilun return -EINVAL;
84477dfdccSXu Yilun
85477dfdccSXu Yilun clear_busy_msk = BIT_ULL(EMIF_STAT_CLEAR_BUSY_SFT + eattr->index);
86477dfdccSXu Yilun clear_en_msk = BIT_ULL(EMIF_CTRL_CLEAR_EN_SFT + eattr->index);
87477dfdccSXu Yilun
88477dfdccSXu Yilun spin_lock(&de->lock);
89477dfdccSXu Yilun /* The CLEAR_EN field is WO, but other fields are RW */
90477dfdccSXu Yilun val = readq(base + EMIF_CTRL);
91477dfdccSXu Yilun val &= ~EMIF_CTRL_CLEAR_EN_MSK;
92477dfdccSXu Yilun val |= clear_en_msk;
93477dfdccSXu Yilun writeq(val, base + EMIF_CTRL);
94477dfdccSXu Yilun spin_unlock(&de->lock);
95477dfdccSXu Yilun
96477dfdccSXu Yilun if (readq_poll_timeout(base + EMIF_STAT, val,
97477dfdccSXu Yilun !(val & clear_busy_msk),
98477dfdccSXu Yilun EMIF_POLL_INVL, EMIF_POLL_TIMEOUT)) {
99477dfdccSXu Yilun dev_err(de->dev, "timeout, fail to clear\n");
100477dfdccSXu Yilun return -ETIMEDOUT;
101477dfdccSXu Yilun }
102477dfdccSXu Yilun
103477dfdccSXu Yilun return count;
104477dfdccSXu Yilun }
105477dfdccSXu Yilun
106477dfdccSXu Yilun #define emif_state_attr(_name, _shift, _index) \
107477dfdccSXu Yilun static struct emif_attr emif_attr_##inf##_index##_##_name = \
108477dfdccSXu Yilun { .attr = __ATTR(inf##_index##_##_name, 0444, \
109477dfdccSXu Yilun emif_state_show, NULL), \
110477dfdccSXu Yilun .shift = (_shift), .index = (_index) }
111477dfdccSXu Yilun
112477dfdccSXu Yilun #define emif_clear_attr(_index) \
113477dfdccSXu Yilun static struct emif_attr emif_attr_##inf##_index##_clear = \
114477dfdccSXu Yilun { .attr = __ATTR(inf##_index##_clear, 0200, \
115477dfdccSXu Yilun NULL, emif_clear_store), \
116477dfdccSXu Yilun .index = (_index) }
117477dfdccSXu Yilun
118477dfdccSXu Yilun emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 0);
119477dfdccSXu Yilun emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 1);
120477dfdccSXu Yilun emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 2);
121477dfdccSXu Yilun emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 3);
122*8e478758SDebarati Biswas emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 4);
123*8e478758SDebarati Biswas emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 5);
124*8e478758SDebarati Biswas emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 6);
125*8e478758SDebarati Biswas emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 7);
126477dfdccSXu Yilun
127477dfdccSXu Yilun emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 0);
128477dfdccSXu Yilun emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 1);
129477dfdccSXu Yilun emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 2);
130477dfdccSXu Yilun emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 3);
131*8e478758SDebarati Biswas emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 4);
132*8e478758SDebarati Biswas emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 5);
133*8e478758SDebarati Biswas emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 6);
134*8e478758SDebarati Biswas emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 7);
135*8e478758SDebarati Biswas
136477dfdccSXu Yilun
137477dfdccSXu Yilun emif_clear_attr(0);
138477dfdccSXu Yilun emif_clear_attr(1);
139477dfdccSXu Yilun emif_clear_attr(2);
140477dfdccSXu Yilun emif_clear_attr(3);
141*8e478758SDebarati Biswas emif_clear_attr(4);
142*8e478758SDebarati Biswas emif_clear_attr(5);
143*8e478758SDebarati Biswas emif_clear_attr(6);
144*8e478758SDebarati Biswas emif_clear_attr(7);
145*8e478758SDebarati Biswas
146477dfdccSXu Yilun
147477dfdccSXu Yilun static struct attribute *dfl_emif_attrs[] = {
148477dfdccSXu Yilun &emif_attr_inf0_init_done.attr.attr,
149477dfdccSXu Yilun &emif_attr_inf0_cal_fail.attr.attr,
150477dfdccSXu Yilun &emif_attr_inf0_clear.attr.attr,
151477dfdccSXu Yilun
152477dfdccSXu Yilun &emif_attr_inf1_init_done.attr.attr,
153477dfdccSXu Yilun &emif_attr_inf1_cal_fail.attr.attr,
154477dfdccSXu Yilun &emif_attr_inf1_clear.attr.attr,
155477dfdccSXu Yilun
156477dfdccSXu Yilun &emif_attr_inf2_init_done.attr.attr,
157477dfdccSXu Yilun &emif_attr_inf2_cal_fail.attr.attr,
158477dfdccSXu Yilun &emif_attr_inf2_clear.attr.attr,
159477dfdccSXu Yilun
160477dfdccSXu Yilun &emif_attr_inf3_init_done.attr.attr,
161477dfdccSXu Yilun &emif_attr_inf3_cal_fail.attr.attr,
162477dfdccSXu Yilun &emif_attr_inf3_clear.attr.attr,
163477dfdccSXu Yilun
164*8e478758SDebarati Biswas &emif_attr_inf4_init_done.attr.attr,
165*8e478758SDebarati Biswas &emif_attr_inf4_cal_fail.attr.attr,
166*8e478758SDebarati Biswas &emif_attr_inf4_clear.attr.attr,
167*8e478758SDebarati Biswas
168*8e478758SDebarati Biswas &emif_attr_inf5_init_done.attr.attr,
169*8e478758SDebarati Biswas &emif_attr_inf5_cal_fail.attr.attr,
170*8e478758SDebarati Biswas &emif_attr_inf5_clear.attr.attr,
171*8e478758SDebarati Biswas
172*8e478758SDebarati Biswas &emif_attr_inf6_init_done.attr.attr,
173*8e478758SDebarati Biswas &emif_attr_inf6_cal_fail.attr.attr,
174*8e478758SDebarati Biswas &emif_attr_inf6_clear.attr.attr,
175*8e478758SDebarati Biswas
176*8e478758SDebarati Biswas &emif_attr_inf7_init_done.attr.attr,
177*8e478758SDebarati Biswas &emif_attr_inf7_cal_fail.attr.attr,
178*8e478758SDebarati Biswas &emif_attr_inf7_clear.attr.attr,
179*8e478758SDebarati Biswas
180477dfdccSXu Yilun NULL,
181477dfdccSXu Yilun };
182477dfdccSXu Yilun
dfl_emif_visible(struct kobject * kobj,struct attribute * attr,int n)183477dfdccSXu Yilun static umode_t dfl_emif_visible(struct kobject *kobj,
184477dfdccSXu Yilun struct attribute *attr, int n)
185477dfdccSXu Yilun {
186477dfdccSXu Yilun struct dfl_emif *de = dev_get_drvdata(kobj_to_dev(kobj));
187477dfdccSXu Yilun struct emif_attr *eattr = container_of(attr, struct emif_attr,
188477dfdccSXu Yilun attr.attr);
189*8e478758SDebarati Biswas struct dfl_device *ddev = to_dfl_dev(de->dev);
190477dfdccSXu Yilun u64 val;
191477dfdccSXu Yilun
192477dfdccSXu Yilun /*
193*8e478758SDebarati Biswas * This device supports up to 8 memory interfaces, but not all
194477dfdccSXu Yilun * interfaces are used on different platforms. The read out value of
195*8e478758SDebarati Biswas * CAPABILITY_CHN_MSK field (which is a bitmap) indicates which
196*8e478758SDebarati Biswas * interfaces are available.
197477dfdccSXu Yilun */
198*8e478758SDebarati Biswas if (ddev->revision > 0 && strstr(attr->name, "_clear"))
199*8e478758SDebarati Biswas return 0;
200*8e478758SDebarati Biswas
201*8e478758SDebarati Biswas if (ddev->revision == 0)
202*8e478758SDebarati Biswas val = FIELD_GET(EMIF_CAPABILITY_CHN_MSK_V0,
203*8e478758SDebarati Biswas readq(de->base + EMIF_CAPABILITY_BASE));
204*8e478758SDebarati Biswas else
205*8e478758SDebarati Biswas val = FIELD_GET(EMIF_CAPABILITY_CHN_MSK,
206*8e478758SDebarati Biswas readq(de->base + EMIF_CAPABILITY_BASE));
207477dfdccSXu Yilun
208477dfdccSXu Yilun return (val & BIT_ULL(eattr->index)) ? attr->mode : 0;
209477dfdccSXu Yilun }
210477dfdccSXu Yilun
211477dfdccSXu Yilun static const struct attribute_group dfl_emif_group = {
212477dfdccSXu Yilun .is_visible = dfl_emif_visible,
213477dfdccSXu Yilun .attrs = dfl_emif_attrs,
214477dfdccSXu Yilun };
215477dfdccSXu Yilun
216477dfdccSXu Yilun static const struct attribute_group *dfl_emif_groups[] = {
217477dfdccSXu Yilun &dfl_emif_group,
218477dfdccSXu Yilun NULL,
219477dfdccSXu Yilun };
220477dfdccSXu Yilun
dfl_emif_probe(struct dfl_device * ddev)221477dfdccSXu Yilun static int dfl_emif_probe(struct dfl_device *ddev)
222477dfdccSXu Yilun {
223477dfdccSXu Yilun struct device *dev = &ddev->dev;
224477dfdccSXu Yilun struct dfl_emif *de;
225477dfdccSXu Yilun
226477dfdccSXu Yilun de = devm_kzalloc(dev, sizeof(*de), GFP_KERNEL);
227477dfdccSXu Yilun if (!de)
228477dfdccSXu Yilun return -ENOMEM;
229477dfdccSXu Yilun
230477dfdccSXu Yilun de->base = devm_ioremap_resource(dev, &ddev->mmio_res);
231477dfdccSXu Yilun if (IS_ERR(de->base))
232477dfdccSXu Yilun return PTR_ERR(de->base);
233477dfdccSXu Yilun
234477dfdccSXu Yilun de->dev = dev;
235477dfdccSXu Yilun spin_lock_init(&de->lock);
236477dfdccSXu Yilun dev_set_drvdata(dev, de);
237477dfdccSXu Yilun
238477dfdccSXu Yilun return 0;
239477dfdccSXu Yilun }
240477dfdccSXu Yilun
241477dfdccSXu Yilun static const struct dfl_device_id dfl_emif_ids[] = {
242477dfdccSXu Yilun { FME_ID, FME_FEATURE_ID_EMIF },
243477dfdccSXu Yilun { }
244477dfdccSXu Yilun };
245477dfdccSXu Yilun MODULE_DEVICE_TABLE(dfl, dfl_emif_ids);
246477dfdccSXu Yilun
247477dfdccSXu Yilun static struct dfl_driver dfl_emif_driver = {
248477dfdccSXu Yilun .drv = {
249477dfdccSXu Yilun .name = "dfl-emif",
250477dfdccSXu Yilun .dev_groups = dfl_emif_groups,
251477dfdccSXu Yilun },
252477dfdccSXu Yilun .id_table = dfl_emif_ids,
253477dfdccSXu Yilun .probe = dfl_emif_probe,
254477dfdccSXu Yilun };
255477dfdccSXu Yilun module_dfl_driver(dfl_emif_driver);
256477dfdccSXu Yilun
257477dfdccSXu Yilun MODULE_DESCRIPTION("DFL EMIF driver");
258477dfdccSXu Yilun MODULE_AUTHOR("Intel Corporation");
259477dfdccSXu Yilun MODULE_LICENSE("GPL v2");
260