2 * $Header: /home/cvs/BIR/ca-cpu/freebios/src/superio/smsc/lpc47n217/superio.c,v 1.1.1.1 2005/07/11 15:28:51 smagnani Exp $
\r
4 * superio.c: RAM-based driver for SMSC LPC47N217 Super I/O chip
\r
6 * Based on LinuxBIOS code for SMSC 47B397:
\r
7 * Copyright 2000 AG Electronics Ltd.
\r
8 * Copyright 2003-2004 Linux Networx
\r
9 * Copyright 2004 Tyan
\r
11 * Copyright (C) 2005 Digital Design Corporation
\r
13 * This program is free software; you can redistribute it and/or modify
\r
14 * it under the terms of the GNU General Public License as published by
\r
15 * the Free Software Foundation; either version 2 of the License, or
\r
16 * (at your option) any later version.
\r
18 * This program is distributed in the hope that it will be useful,
\r
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
21 * GNU General Public License for more details.
\r
23 * You should have received a copy of the GNU General Public License
\r
24 * along with this program; if not, write to the Free Software
\r
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
27 * $Log: superio.c,v $
\r
28 * Revision 1.1.1.1 2005/07/11 15:28:51 smagnani
\r
34 #include <arch/io.h>
\r
35 #include <device/device.h>
\r
36 #include <device/pnp.h>
\r
37 #include <console/console.h>
\r
38 #include <device/smbus.h>
\r
41 #include <uart8250.h>
\r
44 #include "lpc47n217.h"
\r
46 // Forward declarations
\r
47 static void enable_dev(device_t dev);
\r
48 void lpc47n217_pnp_set_resources(device_t dev);
\r
49 void lpc47n217_pnp_enable_resources(device_t dev);
\r
50 void lpc47n217_pnp_enable(device_t dev);
\r
51 static void lpc47n217_init(device_t dev);
\r
53 static void lpc47n217_pnp_set_resource(device_t dev, struct resource *resource);
\r
54 void lpc47n217_pnp_set_iobase(device_t dev, unsigned iobase);
\r
55 void lpc47n217_pnp_set_drq(device_t dev, unsigned drq);
\r
56 void lpc47n217_pnp_set_irq(device_t dev, unsigned irq);
\r
57 void lpc47n217_pnp_set_enable(device_t dev, int enable);
\r
59 static void pnp_enter_conf_state(device_t dev);
\r
60 static void pnp_exit_conf_state(device_t dev);
\r
63 struct chip_operations superio_smsc_lpc47n217_ops = {
\r
64 CHIP_NAME("smsc lpc47n217")
\r
65 .enable_dev = enable_dev,
\r
68 static struct device_operations ops = {
\r
69 .read_resources = pnp_read_resources,
\r
70 .set_resources = lpc47n217_pnp_set_resources,
\r
71 .enable_resources = lpc47n217_pnp_enable_resources,
\r
72 .enable = lpc47n217_pnp_enable,
\r
73 .init = lpc47n217_init,
\r
76 static struct pnp_info pnp_dev_info[] = {
\r
77 { &ops, LPC47N217_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07f8, 0}, },
\r
78 { &ops, LPC47N217_SP1, PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
\r
79 { &ops, LPC47N217_SP2, PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, }
\r
82 /**********************************************************************************/
\r
83 /* PUBLIC INTERFACE */
\r
84 /**********************************************************************************/
\r
86 //----------------------------------------------------------------------------------
\r
87 // Function: enable_dev
\r
88 // Parameters: dev - pointer to structure describing a Super I/O device
\r
89 // Return Value: None
\r
90 // Description: Create device structures and allocate resources to devices
\r
91 // specified in the pnp_dev_info array (above).
\r
93 static void enable_dev(device_t dev)
\r
95 pnp_enable_devices(dev, &pnp_ops,
\r
96 sizeof(pnp_dev_info)/sizeof(pnp_dev_info[0]),
\r
100 //----------------------------------------------------------------------------------
\r
101 // Function: lpc47n217_pnp_set_resources
\r
102 // Parameters: dev - pointer to structure describing a Super I/O device
\r
103 // Return Value: None
\r
104 // Description: Configure the specified Super I/O device with the resources
\r
105 // (I/O space, etc.) that have been allocate for it.
\r
107 void lpc47n217_pnp_set_resources(device_t dev)
\r
111 pnp_enter_conf_state(dev);
\r
113 // NOTE: Cannot use pnp_set_resources() here because it assumes chip
\r
114 // support for logical devices, which the LPC47N217 doesn't have
\r
115 for(i = 0; i < dev->resources; i++)
\r
116 lpc47n217_pnp_set_resource(dev, &dev->resource[i]);
\r
118 // dump_pnp_device(dev);
\r
120 pnp_exit_conf_state(dev);
\r
123 void lpc47n217_pnp_enable_resources(device_t dev)
\r
125 pnp_enter_conf_state(dev);
\r
127 // NOTE: Cannot use pnp_enable_resources() here because it assumes chip
\r
128 // support for logical devices, which the LPC47N217 doesn't have
\r
129 lpc47n217_pnp_set_enable(dev, 1);
\r
131 pnp_exit_conf_state(dev);
\r
134 void lpc47n217_pnp_enable(device_t dev)
\r
136 pnp_enter_conf_state(dev);
\r
138 // NOTE: Cannot use pnp_set_enable() here because it assumes chip
\r
139 // support for logical devices, which the LPC47N217 doesn't have
\r
142 lpc47n217_pnp_set_enable(dev, 1);
\r
145 lpc47n217_pnp_set_enable(dev, 0);
\r
148 pnp_exit_conf_state(dev);
\r
151 //----------------------------------------------------------------------------------
\r
152 // Function: lpc47n217_init
\r
153 // Parameters: dev - pointer to structure describing a Super I/O device
\r
154 // Return Value: None
\r
155 // Description: Initialize the specified Super I/O device.
\r
156 // Devices other than COM ports are ignored.
\r
157 // For COM ports, we configure the baud rate.
\r
159 static void lpc47n217_init(device_t dev)
\r
161 struct superio_smsc_lpc47n217_config* conf = dev->chip_info;
\r
162 struct resource *res0;
\r
167 switch(dev->path.u.pnp.device) {
\r
168 case LPC47N217_SP1:
\r
169 res0 = find_resource(dev, PNP_IDX_IO0);
\r
170 init_uart8250(res0->base, &conf->com1);
\r
173 case LPC47N217_SP2:
\r
174 res0 = find_resource(dev, PNP_IDX_IO0);
\r
175 init_uart8250(res0->base, &conf->com2);
\r
181 /**********************************************************************************/
\r
182 /* PRIVATE FUNCTIONS */
\r
183 /**********************************************************************************/
\r
185 static void lpc47n217_pnp_set_resource(device_t dev, struct resource *resource)
\r
187 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
\r
188 printk_err("ERROR: %s %02x not allocated\n",
\r
189 dev_path(dev), resource->index);
\r
193 /* Now store the resource */
\r
194 // NOTE: Cannot use pnp_set_XXX() here because they assume chip
\r
195 // support for logical devices, which the LPC47N217 doesn't have
\r
197 if (resource->flags & IORESOURCE_IO) {
\r
198 lpc47n217_pnp_set_iobase(dev, resource->base);
\r
200 else if (resource->flags & IORESOURCE_DRQ) {
\r
201 lpc47n217_pnp_set_drq(dev, resource->base);
\r
203 else if (resource->flags & IORESOURCE_IRQ) {
\r
204 lpc47n217_pnp_set_irq(dev, resource->base);
\r
207 printk_err("ERROR: %s %02x unknown resource type\n",
\r
208 dev_path(dev), resource->index);
\r
211 resource->flags |= IORESOURCE_STORED;
\r
213 report_resource_stored(dev, resource, "");
\r
216 void lpc47n217_pnp_set_iobase(device_t dev, unsigned iobase)
\r
218 ASSERT(!(iobase & 0x3));
\r
220 switch(dev->path.u.pnp.device) {
\r
221 case LPC47N217_PP:
\r
222 pnp_write_config(dev, 0x23, (iobase >> 2) & 0xff);
\r
225 case LPC47N217_SP1:
\r
226 pnp_write_config(dev, 0x24, (iobase >> 2) & 0xff);
\r
229 case LPC47N217_SP2:
\r
230 pnp_write_config(dev, 0x25, (iobase >> 2) & 0xff);
\r
239 void lpc47n217_pnp_set_drq(device_t dev, unsigned drq)
\r
241 if (dev->path.u.pnp.device == LPC47N217_PP) {
\r
242 const uint8_t PP_DMA_MASK = 0x0F;
\r
243 const uint8_t PP_DMA_SELECTION_REGISTER = 0x26;
\r
244 uint8_t current_config = pnp_read_config(dev, PP_DMA_SELECTION_REGISTER);
\r
245 uint8_t new_config;
\r
247 ASSERT(!(drq & ~PP_DMA_MASK)); // DRQ out of range??
\r
248 new_config = (current_config & ~PP_DMA_MASK) | drq;
\r
249 pnp_write_config(dev, PP_DMA_SELECTION_REGISTER, new_config);
\r
255 void lpc47n217_pnp_set_irq(device_t dev, unsigned irq)
\r
257 uint8_t irq_config_register = 0;
\r
258 uint8_t irq_config_mask = 0;
\r
259 uint8_t current_config;
\r
260 uint8_t new_config;
\r
262 switch(dev->path.u.pnp.device) {
\r
263 case LPC47N217_PP:
\r
264 irq_config_register = 0x27;
\r
265 irq_config_mask = 0x0F;
\r
268 case LPC47N217_SP1:
\r
269 irq_config_register = 0x28;
\r
270 irq_config_mask = 0xF0;
\r
274 case LPC47N217_SP2:
\r
275 irq_config_register = 0x28;
\r
276 irq_config_mask = 0x0F;
\r
284 ASSERT(!(irq & ~irq_config_mask)); // IRQ out of range??
\r
286 current_config = pnp_read_config(dev, irq_config_register);
\r
287 new_config = (current_config & ~irq_config_mask) | irq;
\r
288 pnp_write_config(dev, irq_config_register, new_config);
\r
291 void lpc47n217_pnp_set_enable(device_t dev, int enable)
\r
293 uint8_t power_register = 0;
\r
294 uint8_t power_mask = 0;
\r
295 uint8_t current_power;
\r
298 switch(dev->path.u.pnp.device) {
\r
299 case LPC47N217_PP:
\r
300 power_register = 0x01;
\r
304 case LPC47N217_SP1:
\r
305 power_register = 0x02;
\r
309 case LPC47N217_SP2:
\r
310 power_register = 0x02;
\r
319 current_power = pnp_read_config(dev, power_register);
\r
320 new_power = current_power & ~power_mask; // disable by default
\r
323 struct resource* ioport_resource = find_resource(dev, PNP_IDX_IO0);
\r
324 lpc47n217_pnp_set_iobase(dev, ioport_resource->base);
\r
326 new_power |= power_mask; // Enable
\r
329 lpc47n217_pnp_set_iobase(dev, 0);
\r
331 pnp_write_config(dev, power_register, new_power);
\r
335 //----------------------------------------------------------------------------------
\r
336 // Function: pnp_enter_conf_state
\r
337 // Parameters: dev - pointer to structure describing a Super I/O device
\r
338 // Return Value: None
\r
339 // Description: Enable access to the LPC47N217's configuration registers.
\r
341 static void pnp_enter_conf_state(device_t dev)
\r
343 outb(0x55, dev->path.u.pnp.port);
\r
346 //----------------------------------------------------------------------------------
\r
347 // Function: pnp_exit_conf_state
\r
348 // Parameters: dev - pointer to structure describing a Super I/O device
\r
349 // Return Value: None
\r
350 // Description: Disable access to the LPC47N217's configuration registers.
\r
352 static void pnp_exit_conf_state(device_t dev)
\r
354 outb(0xaa, dev->path.u.pnp.port);
\r
358 //----------------------------------------------------------------------------------
\r
359 // Function: dump_pnp_device
\r
360 // Parameters: dev - pointer to structure describing a Super I/O device
\r
361 // Return Value: None
\r
362 // Description: Print the values of all of the LPC47N217's configuration registers.
\r
363 // NOTE: The LPC47N217 must be in configuration mode when this
\r
364 // function is called.
\r
366 static void dump_pnp_device(device_t dev)
\r
368 int register_index;
\r
369 print_debug("\r\n");
\r
371 for(register_index = 0; register_index <= LPC47N217_MAX_CONFIG_REGISTER; register_index++) {
\r
372 uint8_t register_value;
\r
374 if ((register_index & 0x0f) == 0) {
\r
375 print_debug_hex8(register_index);
\r
376 print_debug_char(':');
\r
379 // Skip over 'register' that would cause exit from configuration mode
\r
380 if (register_index == 0xaa)
\r
381 register_value = 0xaa;
\r
383 register_value = pnp_read_config(dev, register_index);
\r
385 print_debug_char(' ');
\r
386 print_debug_hex8(register_value);
\r
387 if ((register_index & 0x0f) == 0x0f) {
\r
388 print_debug("\r\n");
\r
392 print_debug("\r\n");
\r