Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/platform/geode/alix.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* System Specific setup for PCEngines ALIX.
4
* At the moment this means setup of GPIO control of LEDs
5
* on Alix.2/3/6 boards.
6
*
7
* Copyright (C) 2008 Constantin Baranov <[email protected]>
8
* Copyright (C) 2011 Ed Wildgoose <[email protected]>
9
* and Philip Prindeville <[email protected]>
10
*
11
* TODO: There are large similarities with leds-net5501.c
12
* by Alessandro Zummo <[email protected]>
13
* In the future leds-net5501.c should be migrated over to platform
14
*/
15
16
#include <linux/kernel.h>
17
#include <linux/init.h>
18
#include <linux/io.h>
19
#include <linux/string.h>
20
#include <linux/moduleparam.h>
21
#include <linux/dmi.h>
22
23
#include <asm/geode.h>
24
25
#include "geode-common.h"
26
27
#define BIOS_SIGNATURE_TINYBIOS 0xf0000
28
#define BIOS_SIGNATURE_COREBOOT 0x500
29
#define BIOS_REGION_SIZE 0x10000
30
31
/*
32
* This driver is not modular, but to keep back compatibility
33
* with existing use cases, continuing with module_param is
34
* the easiest way forward.
35
*/
36
static bool force = 0;
37
module_param(force, bool, 0444);
38
/* FIXME: Award bios is not automatically detected as Alix platform */
39
MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
40
41
static const struct geode_led alix_leds[] __initconst = {
42
{ 6, true },
43
{ 25, false },
44
{ 27, false },
45
};
46
47
static void __init register_alix(void)
48
{
49
geode_create_restart_key(24);
50
geode_create_leds("alix", alix_leds, ARRAY_SIZE(alix_leds));
51
}
52
53
static bool __init alix_present(unsigned long bios_phys,
54
const char *alix_sig,
55
size_t alix_sig_len)
56
{
57
const size_t bios_len = BIOS_REGION_SIZE;
58
const char *bios_virt;
59
const char *scan_end;
60
const char *p;
61
char name[64];
62
63
if (force) {
64
printk(KERN_NOTICE "%s: forced to skip BIOS test, "
65
"assume system is ALIX.2/ALIX.3\n",
66
KBUILD_MODNAME);
67
return true;
68
}
69
70
bios_virt = phys_to_virt(bios_phys);
71
scan_end = bios_virt + bios_len - (alix_sig_len + 2);
72
for (p = bios_virt; p < scan_end; p++) {
73
const char *tail;
74
char *a;
75
76
if (memcmp(p, alix_sig, alix_sig_len) != 0)
77
continue;
78
79
memcpy(name, p, sizeof(name));
80
81
/* remove the first \0 character from string */
82
a = strchr(name, '\0');
83
if (a)
84
*a = ' ';
85
86
/* cut the string at a newline */
87
a = strchr(name, '\r');
88
if (a)
89
*a = '\0';
90
91
tail = p + alix_sig_len;
92
if ((tail[0] == '2' || tail[0] == '3' || tail[0] == '6')) {
93
printk(KERN_INFO
94
"%s: system is recognized as \"%s\"\n",
95
KBUILD_MODNAME, name);
96
return true;
97
}
98
}
99
100
return false;
101
}
102
103
static bool __init alix_present_dmi(void)
104
{
105
const char *vendor, *product;
106
107
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
108
if (!vendor || strcmp(vendor, "PC Engines"))
109
return false;
110
111
product = dmi_get_system_info(DMI_PRODUCT_NAME);
112
if (!product || (strcmp(product, "ALIX.2D") && strcmp(product, "ALIX.6")))
113
return false;
114
115
printk(KERN_INFO "%s: system is recognized as \"%s %s\"\n",
116
KBUILD_MODNAME, vendor, product);
117
118
return true;
119
}
120
121
static int __init alix_init(void)
122
{
123
const char tinybios_sig[] = "PC Engines ALIX.";
124
const char coreboot_sig[] = "PC Engines\0ALIX.";
125
126
if (!is_geode())
127
return 0;
128
129
if (alix_present(BIOS_SIGNATURE_TINYBIOS, tinybios_sig, sizeof(tinybios_sig) - 1) ||
130
alix_present(BIOS_SIGNATURE_COREBOOT, coreboot_sig, sizeof(coreboot_sig) - 1) ||
131
alix_present_dmi())
132
register_alix();
133
134
return 0;
135
}
136
device_initcall(alix_init);
137
138