Merge tag 'soc-fsl-next-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/leo...
[linux-2.6-block.git] / drivers / memory / dfl-emif.c
CommitLineData
477dfdcc
XY
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DFL device driver for EMIF private feature
4 *
5 * Copyright (C) 2020 Intel Corporation, Inc.
6 *
7 */
8#include <linux/bitfield.h>
9#include <linux/dfl.h>
10#include <linux/errno.h>
11#include <linux/io.h>
12#include <linux/iopoll.h>
13#include <linux/io-64-nonatomic-lo-hi.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/spinlock.h>
17#include <linux/types.h>
18
19#define FME_FEATURE_ID_EMIF 0x9
20
21#define EMIF_STAT 0x8
22#define EMIF_STAT_INIT_DONE_SFT 0
23#define EMIF_STAT_CALC_FAIL_SFT 8
24#define EMIF_STAT_CLEAR_BUSY_SFT 16
25#define EMIF_CTRL 0x10
26#define EMIF_CTRL_CLEAR_EN_SFT 0
27#define EMIF_CTRL_CLEAR_EN_MSK GENMASK_ULL(3, 0)
28
29#define EMIF_POLL_INVL 10000 /* us */
30#define EMIF_POLL_TIMEOUT 5000000 /* us */
31
32struct dfl_emif {
33 struct device *dev;
34 void __iomem *base;
35 spinlock_t lock; /* Serialises access to EMIF_CTRL reg */
36};
37
38struct emif_attr {
39 struct device_attribute attr;
40 u32 shift;
41 u32 index;
42};
43
44#define to_emif_attr(dev_attr) \
45 container_of(dev_attr, struct emif_attr, attr)
46
47static ssize_t emif_state_show(struct device *dev,
48 struct device_attribute *attr, char *buf)
49{
50 struct emif_attr *eattr = to_emif_attr(attr);
51 struct dfl_emif *de = dev_get_drvdata(dev);
52 u64 val;
53
54 val = readq(de->base + EMIF_STAT);
55
56 return sysfs_emit(buf, "%u\n",
57 !!(val & BIT_ULL(eattr->shift + eattr->index)));
58}
59
60static ssize_t emif_clear_store(struct device *dev,
61 struct device_attribute *attr,
62 const char *buf, size_t count)
63{
64 struct emif_attr *eattr = to_emif_attr(attr);
65 struct dfl_emif *de = dev_get_drvdata(dev);
66 u64 clear_busy_msk, clear_en_msk, val;
67 void __iomem *base = de->base;
68
69 if (!sysfs_streq(buf, "1"))
70 return -EINVAL;
71
72 clear_busy_msk = BIT_ULL(EMIF_STAT_CLEAR_BUSY_SFT + eattr->index);
73 clear_en_msk = BIT_ULL(EMIF_CTRL_CLEAR_EN_SFT + eattr->index);
74
75 spin_lock(&de->lock);
76 /* The CLEAR_EN field is WO, but other fields are RW */
77 val = readq(base + EMIF_CTRL);
78 val &= ~EMIF_CTRL_CLEAR_EN_MSK;
79 val |= clear_en_msk;
80 writeq(val, base + EMIF_CTRL);
81 spin_unlock(&de->lock);
82
83 if (readq_poll_timeout(base + EMIF_STAT, val,
84 !(val & clear_busy_msk),
85 EMIF_POLL_INVL, EMIF_POLL_TIMEOUT)) {
86 dev_err(de->dev, "timeout, fail to clear\n");
87 return -ETIMEDOUT;
88 }
89
90 return count;
91}
92
93#define emif_state_attr(_name, _shift, _index) \
94 static struct emif_attr emif_attr_##inf##_index##_##_name = \
95 { .attr = __ATTR(inf##_index##_##_name, 0444, \
96 emif_state_show, NULL), \
97 .shift = (_shift), .index = (_index) }
98
99#define emif_clear_attr(_index) \
100 static struct emif_attr emif_attr_##inf##_index##_clear = \
101 { .attr = __ATTR(inf##_index##_clear, 0200, \
102 NULL, emif_clear_store), \
103 .index = (_index) }
104
105emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 0);
106emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 1);
107emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 2);
108emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 3);
109
110emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 0);
111emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 1);
112emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 2);
113emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 3);
114
115emif_clear_attr(0);
116emif_clear_attr(1);
117emif_clear_attr(2);
118emif_clear_attr(3);
119
120static struct attribute *dfl_emif_attrs[] = {
121 &emif_attr_inf0_init_done.attr.attr,
122 &emif_attr_inf0_cal_fail.attr.attr,
123 &emif_attr_inf0_clear.attr.attr,
124
125 &emif_attr_inf1_init_done.attr.attr,
126 &emif_attr_inf1_cal_fail.attr.attr,
127 &emif_attr_inf1_clear.attr.attr,
128
129 &emif_attr_inf2_init_done.attr.attr,
130 &emif_attr_inf2_cal_fail.attr.attr,
131 &emif_attr_inf2_clear.attr.attr,
132
133 &emif_attr_inf3_init_done.attr.attr,
134 &emif_attr_inf3_cal_fail.attr.attr,
135 &emif_attr_inf3_clear.attr.attr,
136
137 NULL,
138};
139
140static umode_t dfl_emif_visible(struct kobject *kobj,
141 struct attribute *attr, int n)
142{
143 struct dfl_emif *de = dev_get_drvdata(kobj_to_dev(kobj));
144 struct emif_attr *eattr = container_of(attr, struct emif_attr,
145 attr.attr);
146 u64 val;
147
148 /*
149 * This device supports upto 4 memory interfaces, but not all
150 * interfaces are used on different platforms. The read out value of
151 * CLEAN_EN field (which is a bitmap) could tell how many interfaces
152 * are available.
153 */
154 val = FIELD_GET(EMIF_CTRL_CLEAR_EN_MSK, readq(de->base + EMIF_CTRL));
155
156 return (val & BIT_ULL(eattr->index)) ? attr->mode : 0;
157}
158
159static const struct attribute_group dfl_emif_group = {
160 .is_visible = dfl_emif_visible,
161 .attrs = dfl_emif_attrs,
162};
163
164static const struct attribute_group *dfl_emif_groups[] = {
165 &dfl_emif_group,
166 NULL,
167};
168
169static int dfl_emif_probe(struct dfl_device *ddev)
170{
171 struct device *dev = &ddev->dev;
172 struct dfl_emif *de;
173
174 de = devm_kzalloc(dev, sizeof(*de), GFP_KERNEL);
175 if (!de)
176 return -ENOMEM;
177
178 de->base = devm_ioremap_resource(dev, &ddev->mmio_res);
179 if (IS_ERR(de->base))
180 return PTR_ERR(de->base);
181
182 de->dev = dev;
183 spin_lock_init(&de->lock);
184 dev_set_drvdata(dev, de);
185
186 return 0;
187}
188
189static const struct dfl_device_id dfl_emif_ids[] = {
190 { FME_ID, FME_FEATURE_ID_EMIF },
191 { }
192};
193MODULE_DEVICE_TABLE(dfl, dfl_emif_ids);
194
195static struct dfl_driver dfl_emif_driver = {
196 .drv = {
197 .name = "dfl-emif",
198 .dev_groups = dfl_emif_groups,
199 },
200 .id_table = dfl_emif_ids,
201 .probe = dfl_emif_probe,
202};
203module_dfl_driver(dfl_emif_driver);
204
205MODULE_DESCRIPTION("DFL EMIF driver");
206MODULE_AUTHOR("Intel Corporation");
207MODULE_LICENSE("GPL v2");