Commit 7f131cf3ed96c969d7b092bf629e25c3df50901e

Authored by Daniel Mack
Committed by Richard Purdie
1 parent a328e95b82

leds: leds-alix2c - take port address from MSR

This makes the LEDs driver for ALIX2.C boards work with Coreboot by
looking up the port address in the MSR rather than hard-coding it.

The BIOS scan also needed some tweaks as the string in Coreboot differs
from the one in the legacy BIOS.

Successfully tested with both the legacy tinyBIOS as well as Coreboot
v3.

Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>

Showing 1 changed file with 84 additions and 31 deletions Side-by-side Diff

drivers/leds/leds-alix2.c
... ... @@ -11,11 +11,24 @@
11 11 #include <linux/module.h>
12 12 #include <linux/platform_device.h>
13 13 #include <linux/string.h>
  14 +#include <linux/pci.h>
14 15  
15 16 static int force = 0;
16 17 module_param(force, bool, 0444);
17 18 MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
18 19  
  20 +#define MSR_LBAR_GPIO 0x5140000C
  21 +#define CS5535_GPIO_SIZE 256
  22 +
  23 +static u32 gpio_base;
  24 +
  25 +static struct pci_device_id divil_pci[] = {
  26 + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
  27 + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
  28 + { } /* NULL entry */
  29 +};
  30 +MODULE_DEVICE_TABLE(pci, divil_pci);
  31 +
19 32 struct alix_led {
20 33 struct led_classdev cdev;
21 34 unsigned short port;
22 35  
... ... @@ -30,9 +43,9 @@
30 43 container_of(led_cdev, struct alix_led, cdev);
31 44  
32 45 if (brightness)
33   - outl(led_dev->on_value, led_dev->port);
  46 + outl(led_dev->on_value, gpio_base + led_dev->port);
34 47 else
35   - outl(led_dev->off_value, led_dev->port);
  48 + outl(led_dev->off_value, gpio_base + led_dev->port);
36 49 }
37 50  
38 51 static struct alix_led alix_leds[] = {
... ... @@ -41,7 +54,7 @@
41 54 .name = "alix:1",
42 55 .brightness_set = alix_led_set,
43 56 },
44   - .port = 0x6100,
  57 + .port = 0x00,
45 58 .on_value = 1 << 22,
46 59 .off_value = 1 << 6,
47 60 },
... ... @@ -50,7 +63,7 @@
50 63 .name = "alix:2",
51 64 .brightness_set = alix_led_set,
52 65 },
53   - .port = 0x6180,
  66 + .port = 0x80,
54 67 .on_value = 1 << 25,
55 68 .off_value = 1 << 9,
56 69 },
... ... @@ -59,7 +72,7 @@
59 72 .name = "alix:3",
60 73 .brightness_set = alix_led_set,
61 74 },
62   - .port = 0x6180,
  75 + .port = 0x80,
63 76 .on_value = 1 << 27,
64 77 .off_value = 1 << 11,
65 78 },
66 79  
67 80  
68 81  
69 82  
70 83  
71 84  
72 85  
73 86  
74 87  
75 88  
76 89  
77 90  
78 91  
79 92  
80 93  
81 94  
... ... @@ -101,65 +114,105 @@
101 114 },
102 115 };
103 116  
104   -static int __init alix_present(void)
  117 +static int __init alix_present(unsigned long bios_phys,
  118 + const char *alix_sig,
  119 + size_t alix_sig_len)
105 120 {
106   - const unsigned long bios_phys = 0x000f0000;
107 121 const size_t bios_len = 0x00010000;
108   - const char alix_sig[] = "PC Engines ALIX.";
109   - const size_t alix_sig_len = sizeof(alix_sig) - 1;
110   -
111 122 const char *bios_virt;
112 123 const char *scan_end;
113 124 const char *p;
114   - int ret = 0;
  125 + char name[64];
115 126  
116 127 if (force) {
117 128 printk(KERN_NOTICE "%s: forced to skip BIOS test, "
118 129 "assume system has ALIX.2 style LEDs\n",
119 130 KBUILD_MODNAME);
120   - ret = 1;
121   - goto out;
  131 + return 1;
122 132 }
123 133  
124 134 bios_virt = phys_to_virt(bios_phys);
125 135 scan_end = bios_virt + bios_len - (alix_sig_len + 2);
126 136 for (p = bios_virt; p < scan_end; p++) {
127 137 const char *tail;
  138 + char *a;
128 139  
129   - if (memcmp(p, alix_sig, alix_sig_len) != 0) {
  140 + if (memcmp(p, alix_sig, alix_sig_len) != 0)
130 141 continue;
131   - }
132 142  
  143 + memcpy(name, p, sizeof(name));
  144 +
  145 + /* remove the first \0 character from string */
  146 + a = strchr(name, '\0');
  147 + if (a)
  148 + *a = ' ';
  149 +
  150 + /* cut the string at a newline */
  151 + a = strchr(name, '\r');
  152 + if (a)
  153 + *a = '\0';
  154 +
133 155 tail = p + alix_sig_len;
134   - if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') {
  156 + if ((tail[0] == '2' || tail[0] == '3')) {
135 157 printk(KERN_INFO
136 158 "%s: system is recognized as \"%s\"\n",
137   - KBUILD_MODNAME, p);
138   - ret = 1;
139   - break;
  159 + KBUILD_MODNAME, name);
  160 + return 1;
140 161 }
141 162 }
142 163  
143   -out:
144   - return ret;
  164 + return 0;
145 165 }
146 166  
147 167 static struct platform_device *pdev;
148 168  
149   -static int __init alix_led_init(void)
  169 +static int __init alix_pci_led_init(void)
150 170 {
151   - int ret;
  171 + u32 low, hi;
152 172  
153   - if (!alix_present()) {
154   - ret = -ENODEV;
155   - goto out;
  173 + if (pci_dev_present(divil_pci) == 0) {
  174 + printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
  175 + return -ENODEV;
156 176 }
157 177  
158   - /* enable output on GPIO for LED 1,2,3 */
159   - outl(1 << 6, 0x6104);
160   - outl(1 << 9, 0x6184);
161   - outl(1 << 11, 0x6184);
  178 + /* Grab the GPIO I/O range */
  179 + rdmsr(MSR_LBAR_GPIO, low, hi);
162 180  
  181 + /* Check the mask and whether GPIO is enabled (sanity check) */
  182 + if (hi != 0x0000f001) {
  183 + printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
  184 + return -ENODEV;
  185 + }
  186 +
  187 + /* Mask off the IO base address */
  188 + gpio_base = low & 0x0000ff00;
  189 +
  190 + if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
  191 + printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
  192 + return -ENODEV;
  193 + }
  194 +
  195 + /* Set GPIO function to output */
  196 + outl(1 << 6, gpio_base + 0x04);
  197 + outl(1 << 9, gpio_base + 0x84);
  198 + outl(1 << 11, gpio_base + 0x84);
  199 +
  200 + return 0;
  201 +}
  202 +
  203 +static int __init alix_led_init(void)
  204 +{
  205 + int ret = -ENODEV;
  206 + const char tinybios_sig[] = "PC Engines ALIX.";
  207 + const char coreboot_sig[] = "PC Engines\0ALIX.";
  208 +
  209 + if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
  210 + alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
  211 + ret = alix_pci_led_init();
  212 +
  213 + if (ret < 0)
  214 + return ret;
  215 +
163 216 pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
164 217 if (!IS_ERR(pdev)) {
165 218 ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
... ... @@ -168,7 +221,6 @@
168 221 } else
169 222 ret = PTR_ERR(pdev);
170 223  
171   -out:
172 224 return ret;
173 225 }
174 226  
... ... @@ -176,6 +228,7 @@
176 228 {
177 229 platform_device_unregister(pdev);
178 230 platform_driver_unregister(&alix_led_driver);
  231 + release_region(gpio_base, CS5535_GPIO_SIZE);
179 232 }
180 233  
181 234 module_init(alix_led_init);