xref: /linux/drivers/i2c/busses/i2c-amd-asf-plat.c (revision 47096fc3d064a07c0842f748b99ebf01be120f2b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * AMD Alert Standard Format Platform Driver
4  *
5  * Copyright (c) 2024, Advanced Micro Devices, Inc.
6  * All Rights Reserved.
7  *
8  * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
9  *	    Sanket Goswami <Sanket.Goswami@amd.com>
10  */
11 
12 #include <linux/bitops.h>
13 #include <linux/device.h>
14 #include <linux/devm-helpers.h>
15 #include <linux/errno.h>
16 #include <linux/gfp_types.h>
17 #include <linux/i2c.h>
18 #include <linux/io.h>
19 #include <linux/ioport.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/sprintf.h>
23 
24 #include "i2c-piix4.h"
25 
26 /* ASF register bits */
27 #define ASF_SLV_LISTN	0
28 #define ASF_SLV_INTR	1
29 #define ASF_SLV_RST	4
30 #define ASF_PEC_SP	5
31 #define ASF_DATA_EN	7
32 #define ASF_MSTR_EN	16
33 #define ASF_CLK_EN	17
34 
35 /* ASF address offsets */
36 #define ASFINDEX	(0x07 + piix4_smba)
37 #define ASFLISADDR	(0x09 + piix4_smba)
38 #define ASFSTA		(0x0A + piix4_smba)
39 #define ASFSLVSTA	(0x0D + piix4_smba)
40 #define ASFDATARWPTR	(0x11 + piix4_smba)
41 #define ASFSETDATARDPTR	(0x12 + piix4_smba)
42 #define ASFDATABNKSEL	(0x13 + piix4_smba)
43 #define ASFSLVEN	(0x15 + piix4_smba)
44 
45 #define ASF_BLOCK_MAX_BYTES	72
46 #define ASF_ERROR_STATUS	GENMASK(3, 1)
47 
48 struct amd_asf_dev {
49 	struct i2c_adapter adap;
50 	void __iomem *eoi_base;
51 	struct i2c_client *target;
52 	struct delayed_work work_buf;
53 	struct sb800_mmio_cfg mmio_cfg;
54 	struct resource *port_addr;
55 };
56 
amd_asf_process_target(struct work_struct * work)57 static void amd_asf_process_target(struct work_struct *work)
58 {
59 	struct amd_asf_dev *dev = container_of(work, struct amd_asf_dev, work_buf.work);
60 	unsigned short piix4_smba = dev->port_addr->start;
61 	u8 data[ASF_BLOCK_MAX_BYTES];
62 	u8 bank, reg, cmd;
63 	u8 len = 0, idx, val;
64 
65 	/* Read target status register */
66 	reg = inb_p(ASFSLVSTA);
67 
68 	/* Check if no error bits are set in target status register */
69 	if (reg & ASF_ERROR_STATUS) {
70 		/* Set bank as full */
71 		cmd = 1;
72 		reg |= GENMASK(3, 2);
73 		outb_p(reg, ASFDATABNKSEL);
74 	} else {
75 		/* Read data bank */
76 		reg = inb_p(ASFDATABNKSEL);
77 		bank = (reg & BIT(3)) ? 1 : 0;
78 
79 		/* Set read data bank */
80 		if (bank) {
81 			reg |= BIT(4);
82 			reg &= ~BIT(3);
83 		} else {
84 			reg &= ~BIT(4);
85 			reg &= ~BIT(2);
86 		}
87 
88 		/* Read command register */
89 		outb_p(reg, ASFDATABNKSEL);
90 		cmd = inb_p(ASFINDEX);
91 		len = inb_p(ASFDATARWPTR);
92 
93 		if (len > ASF_BLOCK_MAX_BYTES)
94 			return;
95 
96 		for (idx = 0; idx < len; idx++)
97 			data[idx] = inb_p(ASFINDEX);
98 
99 		/* Clear data bank status */
100 		if (bank) {
101 			reg |= BIT(3);
102 			outb_p(reg, ASFDATABNKSEL);
103 		} else {
104 			reg |= BIT(2);
105 			outb_p(reg, ASFDATABNKSEL);
106 		}
107 	}
108 
109 	outb_p(0, ASFSETDATARDPTR);
110 	if (cmd & BIT(0))
111 		return;
112 
113 	/*
114 	 * Although i2c_slave_event() returns an appropriate error code, we
115 	 * don't check it here because we're operating in the workqueue context.
116 	 */
117 	i2c_slave_event(dev->target, I2C_SLAVE_WRITE_REQUESTED, &val);
118 	for (idx = 0; idx < len; idx++) {
119 		val = data[idx];
120 		i2c_slave_event(dev->target, I2C_SLAVE_WRITE_RECEIVED, &val);
121 	}
122 	i2c_slave_event(dev->target, I2C_SLAVE_STOP, &val);
123 }
124 
amd_asf_update_ioport_target(unsigned short piix4_smba,u8 bit,unsigned long offset,bool set)125 static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit,
126 					 unsigned long offset, bool set)
127 {
128 	unsigned long reg;
129 
130 	reg = inb_p(offset);
131 	__assign_bit(bit, &reg, set);
132 	outb_p(reg, offset);
133 }
134 
amd_asf_update_mmio_target(struct amd_asf_dev * dev,u8 bit,bool set)135 static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set)
136 {
137 	unsigned long reg;
138 
139 	reg = ioread32(dev->mmio_cfg.addr);
140 	__assign_bit(bit, &reg, set);
141 	iowrite32(reg, dev->mmio_cfg.addr);
142 }
143 
amd_asf_setup_target(struct amd_asf_dev * dev)144 static void amd_asf_setup_target(struct amd_asf_dev *dev)
145 {
146 	unsigned short piix4_smba = dev->port_addr->start;
147 
148 	/* Reset both host and target before setting up */
149 	outb_p(0, SMBHSTSTS);
150 	outb_p(0, ASFSLVSTA);
151 	outb_p(0, ASFSTA);
152 
153 	/* Update target address */
154 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, true);
155 	/* Enable target and set the clock */
156 	amd_asf_update_mmio_target(dev, ASF_MSTR_EN, false);
157 	amd_asf_update_mmio_target(dev, ASF_CLK_EN, true);
158 	/* Enable target interrupt */
159 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, true);
160 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, false);
161 	/* Enable PEC and PEC append */
162 	amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true);
163 	amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true);
164 }
165 
amd_asf_access(struct i2c_adapter * adap,u16 addr,u8 command,u8 * data)166 static int amd_asf_access(struct i2c_adapter *adap, u16 addr, u8 command, u8 *data)
167 {
168 	struct amd_asf_dev *dev = i2c_get_adapdata(adap);
169 	unsigned short piix4_smba = dev->port_addr->start;
170 	u8 i, len;
171 
172 	outb_p((addr << 1), SMBHSTADD);
173 	outb_p(command, SMBHSTCMD);
174 	len = data[0];
175 	if (len == 0 || len > ASF_BLOCK_MAX_BYTES)
176 		return -EINVAL;
177 
178 	outb_p(len, SMBHSTDAT0);
179 	/* Reset SMBBLKDAT */
180 	inb_p(SMBHSTCNT);
181 	for (i = 1; i <= len; i++)
182 		outb_p(data[i], SMBBLKDAT);
183 
184 	outb_p(PIIX4_BLOCK_DATA, SMBHSTCNT);
185 	/* Enable PEC and PEC append */
186 	amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true);
187 	amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true);
188 
189 	return piix4_transaction(adap, piix4_smba);
190 }
191 
amd_asf_xfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)192 static int amd_asf_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
193 {
194 	struct amd_asf_dev *dev = i2c_get_adapdata(adap);
195 	unsigned short piix4_smba = dev->port_addr->start;
196 	u8 asf_data[ASF_BLOCK_MAX_BYTES];
197 	struct i2c_msg *dev_msgs = msgs;
198 	u8 prev_port;
199 	int ret;
200 
201 	if (msgs->flags & I2C_M_RD) {
202 		dev_err(&adap->dev, "ASF: Read not supported\n");
203 		return -EOPNOTSUPP;
204 	}
205 
206 	/* Exclude the receive header and PEC */
207 	if (msgs->len > ASF_BLOCK_MAX_BYTES - 3) {
208 		dev_warn(&adap->dev, "ASF: max message length exceeded\n");
209 		return -EOPNOTSUPP;
210 	}
211 
212 	asf_data[0] = dev_msgs->len;
213 	memcpy(asf_data + 1, dev_msgs[0].buf, dev_msgs->len);
214 
215 	ret = piix4_sb800_region_request(&adap->dev, &dev->mmio_cfg);
216 	if (ret)
217 		return ret;
218 
219 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true);
220 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, false);
221 	/* Clear ASF target status */
222 	outb_p(0, ASFSLVSTA);
223 
224 	/* Enable ASF SMBus controller function */
225 	amd_asf_update_mmio_target(dev, ASF_MSTR_EN, true);
226 	prev_port = piix4_sb800_port_sel(0, &dev->mmio_cfg);
227 	ret = amd_asf_access(adap, msgs->addr, msgs[0].buf[0], asf_data);
228 	piix4_sb800_port_sel(prev_port, &dev->mmio_cfg);
229 	amd_asf_setup_target(dev);
230 	piix4_sb800_region_release(&adap->dev, &dev->mmio_cfg);
231 	return ret;
232 }
233 
amd_asf_reg_target(struct i2c_client * target)234 static int amd_asf_reg_target(struct i2c_client *target)
235 {
236 	struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter);
237 	unsigned short piix4_smba = dev->port_addr->start;
238 	int ret;
239 	u8 reg;
240 
241 	if (dev->target)
242 		return -EBUSY;
243 
244 	ret = piix4_sb800_region_request(&target->dev, &dev->mmio_cfg);
245 	if (ret)
246 		return ret;
247 
248 	reg = (target->addr << 1) | I2C_M_RD;
249 	outb_p(reg, ASFLISADDR);
250 
251 	amd_asf_setup_target(dev);
252 	dev->target = target;
253 	amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, ASFDATABNKSEL, false);
254 	piix4_sb800_region_release(&target->dev, &dev->mmio_cfg);
255 
256 	return 0;
257 }
258 
amd_asf_unreg_target(struct i2c_client * target)259 static int amd_asf_unreg_target(struct i2c_client *target)
260 {
261 	struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter);
262 	unsigned short piix4_smba = dev->port_addr->start;
263 
264 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, false);
265 	amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true);
266 	dev->target = NULL;
267 
268 	return 0;
269 }
270 
amd_asf_func(struct i2c_adapter * adapter)271 static u32 amd_asf_func(struct i2c_adapter *adapter)
272 {
273 	return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
274 	       I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE;
275 }
276 
277 static const struct i2c_algorithm amd_asf_smbus_algorithm = {
278 	.xfer = amd_asf_xfer,
279 	.reg_target = amd_asf_reg_target,
280 	.unreg_target = amd_asf_unreg_target,
281 	.functionality = amd_asf_func,
282 };
283 
amd_asf_irq_handler(int irq,void * ptr)284 static irqreturn_t amd_asf_irq_handler(int irq, void *ptr)
285 {
286 	struct amd_asf_dev *dev = ptr;
287 	unsigned short piix4_smba = dev->port_addr->start;
288 	u8 target_int = inb_p(ASFSTA);
289 
290 	if (target_int & BIT(6)) {
291 		/* Target Interrupt */
292 		outb_p(target_int | BIT(6), ASFSTA);
293 		schedule_delayed_work(&dev->work_buf, HZ);
294 	} else {
295 		/* Controller Interrupt */
296 		amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, SMBHSTSTS, true);
297 	}
298 
299 	iowrite32(irq, dev->eoi_base);
300 	return IRQ_HANDLED;
301 }
302 
amd_asf_probe(struct platform_device * pdev)303 static int amd_asf_probe(struct platform_device *pdev)
304 {
305 	struct device *dev = &pdev->dev;
306 	struct amd_asf_dev *asf_dev;
307 	struct resource *eoi_addr;
308 	int ret, irq;
309 
310 	asf_dev = devm_kzalloc(dev, sizeof(*asf_dev), GFP_KERNEL);
311 	if (!asf_dev)
312 		return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n");
313 
314 	asf_dev->mmio_cfg.use_mmio = true;
315 	asf_dev->port_addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
316 	if (!asf_dev->port_addr)
317 		return dev_err_probe(dev, -EINVAL, "missing IO resources\n");
318 
319 	/*
320 	 * The resource obtained via ACPI might not belong to the ASF device address space. Instead,
321 	 * it could be within other IP blocks of the ASIC, which are crucial for generating
322 	 * subsequent interrupts. Therefore, we avoid using devm_platform_ioremap_resource() and
323 	 * use platform_get_resource() and devm_ioremap() separately to prevent any address space
324 	 * conflicts.
325 	 */
326 	eoi_addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
327 	if (!eoi_addr)
328 		return dev_err_probe(dev, -EINVAL, "missing MEM resources\n");
329 
330 	asf_dev->eoi_base = devm_ioremap(dev, eoi_addr->start, resource_size(eoi_addr));
331 	if (!asf_dev->eoi_base)
332 		return dev_err_probe(dev, -EBUSY, "failed mapping IO region\n");
333 
334 	ret = devm_delayed_work_autocancel(dev, &asf_dev->work_buf, amd_asf_process_target);
335 	if (ret)
336 		return dev_err_probe(dev, ret, "failed to create work queue\n");
337 
338 	irq = platform_get_irq(pdev, 0);
339 	if (irq < 0)
340 		return irq;
341 
342 	ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev);
343 	if (ret)
344 		return ret;
345 
346 	asf_dev->adap.owner = THIS_MODULE;
347 	asf_dev->adap.algo = &amd_asf_smbus_algorithm;
348 	asf_dev->adap.dev.parent = dev;
349 
350 	i2c_set_adapdata(&asf_dev->adap, asf_dev);
351 	snprintf(asf_dev->adap.name, sizeof(asf_dev->adap.name), "AMD ASF adapter");
352 
353 	return devm_i2c_add_adapter(dev, &asf_dev->adap);
354 }
355 
356 static const struct acpi_device_id amd_asf_acpi_ids[] = {
357 	{ "AMDI001A" },
358 	{ }
359 };
360 MODULE_DEVICE_TABLE(acpi, amd_asf_acpi_ids);
361 
362 static struct platform_driver amd_asf_driver = {
363 	.driver = {
364 		.name = "i2c-amd-asf",
365 		.acpi_match_table = amd_asf_acpi_ids,
366 	},
367 	.probe = amd_asf_probe,
368 };
369 module_platform_driver(amd_asf_driver);
370 
371 MODULE_IMPORT_NS("PIIX4_SMBUS");
372 MODULE_LICENSE("GPL");
373 MODULE_DESCRIPTION("AMD Alert Standard Format Driver");
374