xref: /openbmc/linux/drivers/memory/dfl-emif.c (revision 8e478758)
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