brintos

brintos / linux-shallow public Read only

0
0
Text · 7.1 KiB · da06cd3 Raw
260 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * DFL device driver for EMIF private feature4 *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		0x920 21#define EMIF_STAT			0x822#define EMIF_STAT_INIT_DONE_SFT		023#define EMIF_STAT_CALC_FAIL_SFT		824#define EMIF_STAT_CLEAR_BUSY_SFT	1625#define EMIF_CTRL			0x1026#define EMIF_CTRL_CLEAR_EN_SFT		027#define EMIF_CTRL_CLEAR_EN_MSK		GENMASK_ULL(7, 0)28 29#define EMIF_POLL_INVL			10000 /* us */30#define EMIF_POLL_TIMEOUT		5000000 /* us */31 32/*33 * The Capability Register replaces the Control Register (at the same34 * offset) for EMIF feature revisions > 0. The bitmask that indicates35 * the presence of memory channels exists in both the Capability Register36 * and Control Register definitions. These can be thought of as a C union.37 * The Capability Register definitions are used to check for the existence38 * of a memory channel, and the Control Register definitions are used for39 * managing the memory-clear functionality in revision 0.40 */41#define EMIF_CAPABILITY_BASE		0x1042#define EMIF_CAPABILITY_CHN_MSK_V0	GENMASK_ULL(3, 0)43#define EMIF_CAPABILITY_CHN_MSK		GENMASK_ULL(7, 0)44 45struct dfl_emif {46	struct device *dev;47	void __iomem *base;48	spinlock_t lock;	/* Serialises access to EMIF_CTRL reg */49};50 51struct emif_attr {52	struct device_attribute attr;53	u32 shift;54	u32 index;55};56 57#define to_emif_attr(dev_attr) \58	container_of(dev_attr, struct emif_attr, attr)59 60static ssize_t emif_state_show(struct device *dev,61			       struct device_attribute *attr, char *buf)62{63	struct emif_attr *eattr = to_emif_attr(attr);64	struct dfl_emif *de = dev_get_drvdata(dev);65	u64 val;66 67	val = readq(de->base + EMIF_STAT);68 69	return sysfs_emit(buf, "%u\n",70			  !!(val & BIT_ULL(eattr->shift + eattr->index)));71}72 73static ssize_t emif_clear_store(struct device *dev,74				struct device_attribute *attr,75				const char *buf, size_t count)76{77	struct emif_attr *eattr = to_emif_attr(attr);78	struct dfl_emif *de = dev_get_drvdata(dev);79	u64 clear_busy_msk, clear_en_msk, val;80	void __iomem *base = de->base;81 82	if (!sysfs_streq(buf, "1"))83		return -EINVAL;84 85	clear_busy_msk = BIT_ULL(EMIF_STAT_CLEAR_BUSY_SFT + eattr->index);86	clear_en_msk = BIT_ULL(EMIF_CTRL_CLEAR_EN_SFT + eattr->index);87 88	spin_lock(&de->lock);89	/* The CLEAR_EN field is WO, but other fields are RW */90	val = readq(base + EMIF_CTRL);91	val &= ~EMIF_CTRL_CLEAR_EN_MSK;92	val |= clear_en_msk;93	writeq(val, base + EMIF_CTRL);94	spin_unlock(&de->lock);95 96	if (readq_poll_timeout(base + EMIF_STAT, val,97			       !(val & clear_busy_msk),98			       EMIF_POLL_INVL, EMIF_POLL_TIMEOUT)) {99		dev_err(de->dev, "timeout, fail to clear\n");100		return -ETIMEDOUT;101	}102 103	return count;104}105 106#define emif_state_attr(_name, _shift, _index)				\107	static struct emif_attr emif_attr_##inf##_index##_##_name =	\108		{ .attr = __ATTR(inf##_index##_##_name, 0444,		\109				 emif_state_show, NULL),		\110		  .shift = (_shift), .index = (_index) }111 112#define emif_clear_attr(_index)						\113	static struct emif_attr emif_attr_##inf##_index##_clear =	\114		{ .attr = __ATTR(inf##_index##_clear, 0200,		\115				 NULL, emif_clear_store),		\116		  .index = (_index) }117 118emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 0);119emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 1);120emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 2);121emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 3);122emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 4);123emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 5);124emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 6);125emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 7);126 127emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 0);128emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 1);129emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 2);130emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 3);131emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 4);132emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 5);133emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 6);134emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 7);135 136 137emif_clear_attr(0);138emif_clear_attr(1);139emif_clear_attr(2);140emif_clear_attr(3);141emif_clear_attr(4);142emif_clear_attr(5);143emif_clear_attr(6);144emif_clear_attr(7);145 146 147static struct attribute *dfl_emif_attrs[] = {148	&emif_attr_inf0_init_done.attr.attr,149	&emif_attr_inf0_cal_fail.attr.attr,150	&emif_attr_inf0_clear.attr.attr,151 152	&emif_attr_inf1_init_done.attr.attr,153	&emif_attr_inf1_cal_fail.attr.attr,154	&emif_attr_inf1_clear.attr.attr,155 156	&emif_attr_inf2_init_done.attr.attr,157	&emif_attr_inf2_cal_fail.attr.attr,158	&emif_attr_inf2_clear.attr.attr,159 160	&emif_attr_inf3_init_done.attr.attr,161	&emif_attr_inf3_cal_fail.attr.attr,162	&emif_attr_inf3_clear.attr.attr,163 164	&emif_attr_inf4_init_done.attr.attr,165	&emif_attr_inf4_cal_fail.attr.attr,166	&emif_attr_inf4_clear.attr.attr,167 168	&emif_attr_inf5_init_done.attr.attr,169	&emif_attr_inf5_cal_fail.attr.attr,170	&emif_attr_inf5_clear.attr.attr,171 172	&emif_attr_inf6_init_done.attr.attr,173	&emif_attr_inf6_cal_fail.attr.attr,174	&emif_attr_inf6_clear.attr.attr,175 176	&emif_attr_inf7_init_done.attr.attr,177	&emif_attr_inf7_cal_fail.attr.attr,178	&emif_attr_inf7_clear.attr.attr,179 180	NULL,181};182 183static umode_t dfl_emif_visible(struct kobject *kobj,184				struct attribute *attr, int n)185{186	struct dfl_emif *de = dev_get_drvdata(kobj_to_dev(kobj));187	struct emif_attr *eattr = container_of(attr, struct emif_attr,188					       attr.attr);189	struct dfl_device *ddev = to_dfl_dev(de->dev);190	u64 val;191 192	/*193	 * This device supports up to 8 memory interfaces, but not all194	 * interfaces are used on different platforms. The read out value of195	 * CAPABILITY_CHN_MSK field (which is a bitmap) indicates which196	 * interfaces are available.197	 */198	if (ddev->revision > 0 && strstr(attr->name, "_clear"))199		return 0;200 201	if (ddev->revision == 0)202		val = FIELD_GET(EMIF_CAPABILITY_CHN_MSK_V0,203				readq(de->base + EMIF_CAPABILITY_BASE));204	else205		val = FIELD_GET(EMIF_CAPABILITY_CHN_MSK,206				readq(de->base + EMIF_CAPABILITY_BASE));207 208	return (val & BIT_ULL(eattr->index)) ? attr->mode : 0;209}210 211static const struct attribute_group dfl_emif_group = {212	.is_visible = dfl_emif_visible,213	.attrs = dfl_emif_attrs,214};215 216static const struct attribute_group *dfl_emif_groups[] = {217	&dfl_emif_group,218	NULL,219};220 221static int dfl_emif_probe(struct dfl_device *ddev)222{223	struct device *dev = &ddev->dev;224	struct dfl_emif *de;225 226	de = devm_kzalloc(dev, sizeof(*de), GFP_KERNEL);227	if (!de)228		return -ENOMEM;229 230	de->base = devm_ioremap_resource(dev, &ddev->mmio_res);231	if (IS_ERR(de->base))232		return PTR_ERR(de->base);233 234	de->dev = dev;235	spin_lock_init(&de->lock);236	dev_set_drvdata(dev, de);237 238	return 0;239}240 241static const struct dfl_device_id dfl_emif_ids[] = {242	{ FME_ID, FME_FEATURE_ID_EMIF },243	{ }244};245MODULE_DEVICE_TABLE(dfl, dfl_emif_ids);246 247static struct dfl_driver dfl_emif_driver = {248	.drv	= {249		.name       = "dfl-emif",250		.dev_groups = dfl_emif_groups,251	},252	.id_table = dfl_emif_ids,253	.probe   = dfl_emif_probe,254};255module_dfl_driver(dfl_emif_driver);256 257MODULE_DESCRIPTION("DFL EMIF driver");258MODULE_AUTHOR("Intel Corporation");259MODULE_LICENSE("GPL v2");260