coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
superio.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /* RAM-based driver for SMSC LPC47N217 Super I/O chip. */
4 
5 #include <arch/io.h>
6 #include <device/device.h>
7 #include <device/pnp.h>
8 #include <console/console.h>
9 #include <assert.h>
10 
11 #include "lpc47n217.h"
12 
13 /* Forward declarations */
14 static void enable_dev(struct device *dev);
15 static void lpc47n217_pnp_set_resources(struct device *dev);
16 static void lpc47n217_pnp_enable_resources(struct device *dev);
17 static void lpc47n217_pnp_enable(struct device *dev);
18 static void lpc47n217_init(struct device *dev);
19 static void lpc47n217_pnp_set_resource(struct device *dev, struct resource *resource);
20 static void lpc47n217_pnp_set_iobase(struct device *dev, u16 iobase);
21 static void lpc47n217_pnp_set_drq(struct device *dev, u8 drq);
22 static void lpc47n217_pnp_set_irq(struct device *dev, u8 irq);
23 static void lpc47n217_pnp_set_enable(struct device *dev, int enable);
24 static void pnp_enter_conf_state(struct device *dev);
25 static void pnp_exit_conf_state(struct device *dev);
26 
28  CHIP_NAME("SMSC LPC47N217 Super I/O")
29  .enable_dev = enable_dev,
30 };
31 
32 static struct device_operations ops = {
34  .set_resources = lpc47n217_pnp_set_resources,
35  .enable_resources = lpc47n217_pnp_enable_resources,
36  .enable = lpc47n217_pnp_enable,
37  .init = lpc47n217_init,
38 };
39 
40 static struct pnp_info pnp_dev_info[] = {
41  { NULL, LPC47N217_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, 0x07f8, },
42  { NULL, LPC47N217_SP1, PNP_IO0 | PNP_IRQ0, 0x07f8, },
43  { NULL, LPC47N217_SP2, PNP_IO0 | PNP_IRQ0, 0x07f8, }
44 };
45 
46 /**
47  * Create device structures and allocate resources to devices specified in the
48  * pnp_dev_info array (above).
49  *
50  * @param dev Pointer to structure describing a Super I/O device.
51  */
52 static void enable_dev(struct device *dev)
53 {
55 }
56 
57 /**
58  * Configure the specified Super I/O device with the resources (I/O space,
59  * etc.) that have been allocate for it.
60  *
61  * NOTE: Cannot use pnp_set_resources() here because it assumes chip
62  * support for logical devices, which the LPC47N217 doesn't have.
63  *
64  * @param dev Pointer to structure describing a Super I/O device.
65  */
66 static void lpc47n217_pnp_set_resources(struct device *dev)
67 {
68  struct resource *res;
69 
71  for (res = dev->resource_list; res; res = res->next)
73  /* dump_pnp_device(dev); */
75 }
76 
77 /*
78  * NOTE: Cannot use pnp_enable_resources() here because it assumes chip
79  * support for logical devices, which the LPC47N217 doesn't have.
80  */
81 static void lpc47n217_pnp_enable_resources(struct device *dev)
82 {
86 }
87 
88 /*
89  * NOTE: Cannot use pnp_set_enable() here because it assumes chip
90  * support for logical devices, which the LPC47N217 doesn't have.
91  */
92 static void lpc47n217_pnp_enable(struct device *dev)
93 {
95  lpc47n217_pnp_set_enable(dev, !!dev->enabled);
97 }
98 
99 /**
100  * Initialize the specified Super I/O device.
101  *
102  * Devices other than COM ports are ignored. For COM ports, we configure the
103  * baud rate.
104  *
105  * @param dev Pointer to structure describing a Super I/O device.
106  */
107 static void lpc47n217_init(struct device *dev)
108 {
109  if (!dev->enabled)
110  return;
111 }
112 
113 static void lpc47n217_pnp_set_resource(struct device *dev, struct resource *resource)
114 {
115  if (!(resource->flags & IORESOURCE_ASSIGNED)) {
116  printk(BIOS_ERR, "%s %02lx not allocated\n",
117  dev_path(dev), resource->index);
118  return;
119  }
120 
121  /* Now store the resource. */
122 
123  /*
124  * NOTE: Cannot use pnp_set_XXX() here because they assume chip
125  * support for logical devices, which the LPC47N217 doesn't have.
126  */
127  if (resource->flags & IORESOURCE_IO) {
129  } else if (resource->flags & IORESOURCE_DRQ) {
131  } else if (resource->flags & IORESOURCE_IRQ) {
133  } else {
134  printk(BIOS_ERR, "%s %02lx unknown resource type\n",
135  dev_path(dev), resource->index);
136  return;
137  }
139 
141 }
142 
143 static void lpc47n217_pnp_set_iobase(struct device *dev, u16 iobase)
144 {
145  ASSERT(!(iobase & 0x3));
146 
147  switch (dev->path.pnp.device) {
148  case LPC47N217_PP:
149  pnp_write_config(dev, 0x23, (iobase >> 2) & 0xff);
150  break;
151  case LPC47N217_SP1:
152  pnp_write_config(dev, 0x24, (iobase >> 2) & 0xff);
153  break;
154  case LPC47N217_SP2:
155  pnp_write_config(dev, 0x25, (iobase >> 2) & 0xff);
156  break;
157  default:
158  BUG();
159  break;
160  }
161 }
162 
163 static void lpc47n217_pnp_set_drq(struct device *dev, u8 drq)
164 {
165  const u8 PP_DMA_MASK = 0x0F;
166  const u8 PP_DMA_SELECTION_REGISTER = 0x26;
167  u8 current_config, new_config;
168 
169  if (dev->path.pnp.device == LPC47N217_PP) {
170  current_config = pnp_read_config(dev,
171  PP_DMA_SELECTION_REGISTER);
172  ASSERT(!(drq & ~PP_DMA_MASK)); /* DRQ out of range? */
173  new_config = (current_config & ~PP_DMA_MASK) | drq;
174  pnp_write_config(dev, PP_DMA_SELECTION_REGISTER, new_config);
175  } else {
176  BUG();
177  }
178 }
179 
180 static void lpc47n217_pnp_set_irq(struct device *dev, u8 irq)
181 {
182  u8 irq_config_register = 0, irq_config_mask = 0;
183  u8 current_config, new_config;
184 
185  switch (dev->path.pnp.device) {
186  case LPC47N217_PP:
187  irq_config_register = 0x27;
188  irq_config_mask = 0x0F;
189  break;
190  case LPC47N217_SP1:
191  irq_config_register = 0x28;
192  irq_config_mask = 0xF0;
193  irq <<= 4;
194  break;
195  case LPC47N217_SP2:
196  irq_config_register = 0x28;
197  irq_config_mask = 0x0F;
198  break;
199  default:
200  BUG();
201  return;
202  }
203 
204  ASSERT(!(irq & ~irq_config_mask)); /* IRQ out of range? */
205 
206  current_config = pnp_read_config(dev, irq_config_register);
207  new_config = (current_config & ~irq_config_mask) | irq;
208  pnp_write_config(dev, irq_config_register, new_config);
209 }
210 
211 static void lpc47n217_pnp_set_enable(struct device *dev, int enable)
212 {
213  u8 power_register = 0, power_mask = 0, current_power, new_power;
214 
215  switch (dev->path.pnp.device) {
216  case LPC47N217_PP:
217  power_register = 0x01;
218  power_mask = 0x04;
219  break;
220  case LPC47N217_SP1:
221  power_register = 0x02;
222  power_mask = 0x08;
223  break;
224  case LPC47N217_SP2:
225  power_register = 0x02;
226  power_mask = 0x80;
227  break;
228  default:
229  BUG();
230  return;
231  }
232 
233  current_power = pnp_read_config(dev, power_register);
234  new_power = current_power & ~power_mask; /* Disable by default. */
235  if (enable) {
236  struct resource* ioport_resource;
237  ioport_resource = find_resource(dev, PNP_IDX_IO0);
238  lpc47n217_pnp_set_iobase(dev, ioport_resource->base);
239  new_power |= power_mask; /* Enable. */
240  } else {
241  lpc47n217_pnp_set_iobase(dev, 0);
242  }
243  pnp_write_config(dev, power_register, new_power);
244 }
245 
246 static void pnp_enter_conf_state(struct device *dev)
247 {
248  outb(0x55, dev->path.pnp.port);
249 }
250 
251 static void pnp_exit_conf_state(struct device *dev)
252 {
253  outb(0xaa, dev->path.pnp.port);
254 }
#define BUG()
Definition: assert.h:65
#define ASSERT(x)
Definition: assert.h:44
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define printk(level,...)
Definition: stdlib.h:16
void outb(u8 val, u16 port)
void report_resource_stored(struct device *dev, const struct resource *resource, const char *comment)
Print the resource that was just stored.
Definition: device_util.c:508
struct resource * find_resource(const struct device *dev, unsigned int index)
Return an existing resource structure for a given index.
Definition: device_util.c:394
const char * dev_path(const struct device *dev)
Definition: device_util.c:149
#define CHIP_NAME(X)
Definition: device.h:32
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define LPC47N217_PP
Definition: lpc47n217.h:13
#define LPC47N217_SP2
Definition: lpc47n217.h:15
#define LPC47N217_SP1
Definition: lpc47n217.h:14
#define PNP_DRQ0
Definition: pnp.h:49
#define PNP_IO0
Definition: pnp.h:42
#define PNP_IRQ0
Definition: pnp.h:47
#define PNP_IDX_IO0
Definition: pnp_def.h:5
void pnp_read_resources(struct device *dev)
Definition: pnp_device.c:114
void pnp_enable_devices(struct device *base_dev, struct device_operations *ops, unsigned int functions, struct pnp_info *info)
Definition: pnp_device.c:371
u8 pnp_read_config(struct device *dev, u8 reg)
Definition: pnp_device.c:44
void pnp_write_config(struct device *dev, u8 reg, u8 value)
Definition: pnp_device.c:38
#define IORESOURCE_IRQ
Definition: resource.h:11
#define IORESOURCE_DRQ
Definition: resource.h:12
#define IORESOURCE_STORED
Definition: resource.h:32
#define IORESOURCE_ASSIGNED
Definition: resource.h:34
#define IORESOURCE_IO
Definition: resource.h:9
static void lpc47n217_pnp_set_iobase(struct device *dev, u16 iobase)
Definition: superio.c:143
static void lpc47n217_pnp_enable(struct device *dev)
Definition: superio.c:92
static void pnp_exit_conf_state(struct device *dev)
Definition: superio.c:251
static void lpc47n217_pnp_set_enable(struct device *dev, int enable)
Definition: superio.c:211
static void lpc47n217_pnp_set_resources(struct device *dev)
Configure the specified Super I/O device with the resources (I/O space, etc.) that have been allocate...
Definition: superio.c:66
static void enable_dev(struct device *dev)
Create device structures and allocate resources to devices specified in the pnp_dev_info array (above...
Definition: superio.c:52
static struct device_operations ops
Definition: superio.c:32
static struct pnp_info pnp_dev_info[]
Definition: superio.c:40
static void lpc47n217_init(struct device *dev)
Initialize the specified Super I/O device.
Definition: superio.c:107
static void lpc47n217_pnp_enable_resources(struct device *dev)
Definition: superio.c:81
static void lpc47n217_pnp_set_resource(struct device *dev, struct resource *resource)
Definition: superio.c:113
static void pnp_enter_conf_state(struct device *dev)
Definition: superio.c:246
struct chip_operations superio_smsc_lpc47n217_ops
Definition: superio.c:27
static void lpc47n217_pnp_set_irq(struct device *dev, u8 irq)
Definition: superio.c:180
static void lpc47n217_pnp_set_drq(struct device *dev, u8 drq)
Definition: superio.c:163
#define NULL
Definition: stddef.h:19
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
void(* read_resources)(struct device *dev)
Definition: device.h:39
struct pnp_path pnp
Definition: path.h:117
Definition: device.h:107
struct device_path path
Definition: device.h:115
DEVTREE_CONST struct resource * resource_list
Definition: device.h:134
unsigned int enabled
Definition: device.h:122
Definition: pnp.h:37
unsigned int port
Definition: path.h:58
unsigned int device
Definition: path.h:59
unsigned long flags
Definition: resource.h:49
resource_t base
Definition: resource.h:45
unsigned long index
Definition: resource.h:50
DEVTREE_CONST struct resource * next
Definition: resource.h:48