xref: /openbmc/linux/drivers/platform/x86/ibm_rtl.c (revision 565d76cb)
1 /*
2  * IBM Real-Time Linux driver
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * Copyright (C) IBM Corporation, 2010
19  *
20  * Author: Keith Mannthey <kmannth@us.ibm.com>
21  *         Vernon Mauery <vernux@us.ibm.com>
22  *
23  */
24 
25 #include <linux/kernel.h>
26 #include <linux/delay.h>
27 #include <linux/module.h>
28 #include <linux/io.h>
29 #include <linux/sysdev.h>
30 #include <linux/dmi.h>
31 #include <linux/efi.h>
32 #include <linux/mutex.h>
33 #include <asm/bios_ebda.h>
34 
35 static bool force;
36 module_param(force, bool, 0);
37 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
38 
39 static bool debug;
40 module_param(debug, bool, 0644);
41 MODULE_PARM_DESC(debug, "Show debug output");
42 
43 MODULE_LICENSE("GPL");
44 MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
45 MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
46 
47 #define RTL_ADDR_TYPE_IO    1
48 #define RTL_ADDR_TYPE_MMIO  2
49 
50 #define RTL_CMD_ENTER_PRTM  1
51 #define RTL_CMD_EXIT_PRTM   2
52 
53 /* The RTL table as presented by the EBDA: */
54 struct ibm_rtl_table {
55 	char signature[5]; /* signature should be "_RTL_" */
56 	u8 version;
57 	u8 rt_status;
58 	u8 command;
59 	u8 command_status;
60 	u8 cmd_address_type;
61 	u8 cmd_granularity;
62 	u8 cmd_offset;
63 	u16 reserve1;
64 	u32 cmd_port_address; /* platform dependent address */
65 	u32 cmd_port_value;   /* platform dependent value */
66 } __attribute__((packed));
67 
68 /* to locate "_RTL_" signature do a masked 5-byte integer compare */
69 #define RTL_SIGNATURE 0x0000005f4c54525fULL
70 #define RTL_MASK      0x000000ffffffffffULL
71 
72 #define RTL_DEBUG(A, ...) do { \
73 	if (debug) \
74 		pr_info("ibm-rtl: " A, ##__VA_ARGS__ ); \
75 } while (0)
76 
77 static DEFINE_MUTEX(rtl_lock);
78 static struct ibm_rtl_table __iomem *rtl_table;
79 static void __iomem *ebda_map;
80 static void __iomem *rtl_cmd_addr;
81 static u8 rtl_cmd_type;
82 static u8 rtl_cmd_width;
83 
84 static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
85 {
86 	if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
87 		return ioremap(addr, len);
88 	return ioport_map(addr, len);
89 }
90 
91 static void rtl_port_unmap(void __iomem *addr)
92 {
93 	if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
94 		iounmap(addr);
95 	else
96 		ioport_unmap(addr);
97 }
98 
99 static int ibm_rtl_write(u8 value)
100 {
101 	int ret = 0, count = 0;
102 	static u32 cmd_port_val;
103 
104 	RTL_DEBUG("%s(%d)\n", __FUNCTION__, value);
105 
106 	value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
107 
108 	mutex_lock(&rtl_lock);
109 
110 	if (ioread8(&rtl_table->rt_status) != value) {
111 		iowrite8(value, &rtl_table->command);
112 
113 		switch (rtl_cmd_width) {
114 		case 8:
115 			cmd_port_val = ioread8(&rtl_table->cmd_port_value);
116 			RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
117 			iowrite8((u8)cmd_port_val, rtl_cmd_addr);
118 			break;
119 		case 16:
120 			cmd_port_val = ioread16(&rtl_table->cmd_port_value);
121 			RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
122 			iowrite16((u16)cmd_port_val, rtl_cmd_addr);
123 			break;
124 		case 32:
125 			cmd_port_val = ioread32(&rtl_table->cmd_port_value);
126 			RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
127 			iowrite32(cmd_port_val, rtl_cmd_addr);
128 			break;
129 		}
130 
131 		while (ioread8(&rtl_table->command)) {
132 			msleep(10);
133 			if (count++ > 500) {
134 				pr_err("ibm-rtl: Hardware not responding to "
135 					"mode switch request\n");
136 				ret = -EIO;
137 				break;
138 			}
139 
140 		}
141 
142 		if (ioread8(&rtl_table->command_status)) {
143 			RTL_DEBUG("command_status reports failed command\n");
144 			ret = -EIO;
145 		}
146 	}
147 
148 	mutex_unlock(&rtl_lock);
149 	return ret;
150 }
151 
152 static ssize_t rtl_show_version(struct sysdev_class * dev,
153                                 struct sysdev_class_attribute *attr,
154                                 char *buf)
155 {
156 	return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
157 }
158 
159 static ssize_t rtl_show_state(struct sysdev_class *dev,
160                               struct sysdev_class_attribute *attr,
161                               char *buf)
162 {
163 	return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
164 }
165 
166 static ssize_t rtl_set_state(struct sysdev_class *dev,
167                              struct sysdev_class_attribute *attr,
168                              const char *buf,
169                              size_t count)
170 {
171 	ssize_t ret;
172 
173 	if (count < 1 || count > 2)
174 		return -EINVAL;
175 
176 	switch (buf[0]) {
177 	case '0':
178 		ret = ibm_rtl_write(0);
179 		break;
180 	case '1':
181 		ret = ibm_rtl_write(1);
182 		break;
183 	default:
184 		ret = -EINVAL;
185 	}
186 	if (ret >= 0)
187 		ret = count;
188 
189 	return ret;
190 }
191 
192 static struct sysdev_class class_rtl = {
193 	.name = "ibm_rtl",
194 };
195 
196 static SYSDEV_CLASS_ATTR(version, S_IRUGO, rtl_show_version, NULL);
197 static SYSDEV_CLASS_ATTR(state, 0600, rtl_show_state, rtl_set_state);
198 
199 static struct sysdev_class_attribute *rtl_attributes[] = {
200 	&attr_version,
201 	&attr_state,
202 	NULL
203 };
204 
205 
206 static int rtl_setup_sysfs(void) {
207 	int ret, i;
208 	ret = sysdev_class_register(&class_rtl);
209 
210 	if (!ret) {
211 		for (i = 0; rtl_attributes[i]; i ++)
212 			sysdev_class_create_file(&class_rtl, rtl_attributes[i]);
213 	}
214 	return ret;
215 }
216 
217 static void rtl_teardown_sysfs(void) {
218 	int i;
219 	for (i = 0; rtl_attributes[i]; i ++)
220 		sysdev_class_remove_file(&class_rtl, rtl_attributes[i]);
221 	sysdev_class_unregister(&class_rtl);
222 }
223 
224 
225 static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = {
226 	{                                                  \
227 		.matches = {                               \
228 			DMI_MATCH(DMI_SYS_VENDOR, "IBM"),  \
229 		},                                         \
230 	},
231 	{ }
232 };
233 
234 static int __init ibm_rtl_init(void) {
235 	unsigned long ebda_addr, ebda_size;
236 	unsigned int ebda_kb;
237 	int ret = -ENODEV, i;
238 
239 	if (force)
240 		pr_warning("ibm-rtl: module loaded by force\n");
241 	/* first ensure that we are running on IBM HW */
242 	else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table))
243 		return -ENODEV;
244 
245 	/* Get the address for the Extended BIOS Data Area */
246 	ebda_addr = get_bios_ebda();
247 	if (!ebda_addr) {
248 		RTL_DEBUG("no BIOS EBDA found\n");
249 		return -ENODEV;
250 	}
251 
252 	ebda_map = ioremap(ebda_addr, 4);
253 	if (!ebda_map)
254 		return -ENOMEM;
255 
256 	/* First word in the EDBA is the Size in KB */
257 	ebda_kb = ioread16(ebda_map);
258 	RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
259 
260 	if (ebda_kb == 0)
261 		goto out;
262 
263 	iounmap(ebda_map);
264 	ebda_size = ebda_kb*1024;
265 
266 	/* Remap the whole table */
267 	ebda_map = ioremap(ebda_addr, ebda_size);
268 	if (!ebda_map)
269 		return -ENOMEM;
270 
271 	/* search for the _RTL_ signature at the start of the table */
272 	for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
273 		struct ibm_rtl_table __iomem * tmp;
274 		tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
275 		if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
276 			phys_addr_t addr;
277 			unsigned int plen;
278 			RTL_DEBUG("found RTL_SIGNATURE at %#llx\n", (u64)tmp);
279 			rtl_table = tmp;
280 			/* The address, value, width and offset are platform
281 			 * dependent and found in the ibm_rtl_table */
282 			rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
283 			rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
284 			RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
285 			      rtl_cmd_width, rtl_cmd_type);
286 			addr = ioread32(&rtl_table->cmd_port_address);
287 			RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr);
288 			plen = rtl_cmd_width/sizeof(char);
289 			rtl_cmd_addr = rtl_port_map(addr, plen);
290 			RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr);
291 			if (!rtl_cmd_addr) {
292 				ret = -ENOMEM;
293 				break;
294 			}
295 			ret = rtl_setup_sysfs();
296 			break;
297 		}
298 	}
299 
300 out:
301 	if (ret) {
302 		iounmap(ebda_map);
303 		rtl_port_unmap(rtl_cmd_addr);
304 	}
305 
306 	return ret;
307 }
308 
309 static void __exit ibm_rtl_exit(void)
310 {
311 	if (rtl_table) {
312 		RTL_DEBUG("cleaning up");
313 		/* do not leave the machine in SMI-free mode */
314 		ibm_rtl_write(0);
315 		/* unmap, unlink and remove all traces */
316 		rtl_teardown_sysfs();
317 		iounmap(ebda_map);
318 		rtl_port_unmap(rtl_cmd_addr);
319 	}
320 }
321 
322 module_init(ibm_rtl_init);
323 module_exit(ibm_rtl_exit);
324