blob: f646792e57bad2eea340b47fe94158d23bc876ed [file] [log] [blame]
Stefan Reinauer55426df2010-01-17 13:50:17 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2005 Digital Design Corporation
5 * Copyright (C) 2008-2009 coresystems GmbH
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer55426df2010-01-17 13:50:17 +000015 */
16
17/* Pre-RAM driver for SMSC LPC47N227 Super I/O chip. */
18
Stefan Reinauer24d1d4b2013-03-21 11:51:41 -070019#include <arch/io.h>
Stefan Reinauer55426df2010-01-17 13:50:17 +000020#include "lpc47n227.h"
21
Edward O'Callaghan85836c22014-07-09 20:26:25 +100022static void pnp_enter_conf_state(pnp_devfn_t dev)
Stefan Reinauer55426df2010-01-17 13:50:17 +000023{
Uwe Hermanna69d9782010-11-15 19:35:14 +000024 u16 port = dev >> 8;
Stefan Reinauer55426df2010-01-17 13:50:17 +000025 outb(0x55, port);
26}
27
Edward O'Callaghan85836c22014-07-09 20:26:25 +100028static void pnp_exit_conf_state(pnp_devfn_t dev)
Stefan Reinauer55426df2010-01-17 13:50:17 +000029{
Uwe Hermanna69d9782010-11-15 19:35:14 +000030 u16 port = dev >> 8;
Stefan Reinauer55426df2010-01-17 13:50:17 +000031 outb(0xaa, port);
32}
33
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000034/**
35 * Program the base I/O port for the specified logical device.
36 *
37 * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number.
38 * @param iobase Base I/O port for the logical device.
39 */
Edward O'Callaghan85836c22014-07-09 20:26:25 +100040static void lpc47n227_pnp_set_iobase(pnp_devfn_t dev, u16 iobase)
Stefan Reinauer55426df2010-01-17 13:50:17 +000041{
Uwe Hermanna69d9782010-11-15 19:35:14 +000042 /* LPC47N227 requires base ports to be a multiple of 4. */
Patrick Georgid6350682012-05-18 12:47:02 +020043 /* it's not very useful to do an ASSERT here: if it trips,
44 * there's no console to report it.
Stefan Reinauer55426df2010-01-17 13:50:17 +000045 ASSERT(!(iobase & 0x3));
Patrick Georgid6350682012-05-18 12:47:02 +020046 */
Stefan Reinauer55426df2010-01-17 13:50:17 +000047
48 switch (dev & 0xFF) {
49 case LPC47N227_PP:
50 pnp_write_config(dev, 0x23, (iobase >> 2) & 0xff);
51 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000052 case LPC47N227_SP1:
53 pnp_write_config(dev, 0x24, (iobase >> 2) & 0xff);
54 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000055 case LPC47N227_SP2:
56 pnp_write_config(dev, 0x25, (iobase >> 2) & 0xff);
57 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000058 default:
59 break;
60 }
61}
62
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000063/**
64 * Enable or disable the specified logical device.
65 *
66 * Technically, a full disable requires setting the device's base I/O port
67 * below 0x100. We don't do that here, because we don't have access to a data
68 * structure that specifies what the 'real' base port is (when asked to enable
69 * the device). Also the function is used only to disable the device while its
70 * true base port is programmed (see lpc47n227_enable_serial() below).
71 *
72 * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number.
73 * @param enable 0 to disable, anythig else to enable.
74 */
Edward O'Callaghan85836c22014-07-09 20:26:25 +100075static void lpc47n227_pnp_set_enable(pnp_devfn_t dev, int enable)
Stefan Reinauer55426df2010-01-17 13:50:17 +000076{
Uwe Hermanna69d9782010-11-15 19:35:14 +000077 u8 power_register = 0, power_mask = 0, current_power, new_power;
Stefan Reinauer55426df2010-01-17 13:50:17 +000078
79 switch (dev & 0xFF) {
80 case LPC47N227_PP:
81 power_register = 0x01;
82 power_mask = 0x04;
83 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000084 case LPC47N227_SP1:
85 power_register = 0x02;
86 power_mask = 0x08;
87 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000088 case LPC47N227_SP2:
89 power_register = 0x02;
90 power_mask = 0x80;
91 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000092 default:
93 return;
94 }
95
96 current_power = pnp_read_config(dev, power_register);
Uwe Hermanna69d9782010-11-15 19:35:14 +000097 new_power = current_power & ~power_mask; /* Disable by default. */
Stefan Reinauer55426df2010-01-17 13:50:17 +000098 if (enable)
Uwe Hermanna69d9782010-11-15 19:35:14 +000099 new_power |= power_mask; /* Enable. */
Stefan Reinauer55426df2010-01-17 13:50:17 +0000100 pnp_write_config(dev, power_register, new_power);
101}
102
Uwe Hermannb69cb5a2010-10-26 22:46:43 +0000103/**
104 * Configure the base I/O port of the specified serial device and enable the
105 * serial device.
106 *
107 * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number.
108 * @param iobase Processor I/O port address to assign to this serial device.
109 */
Edward O'Callaghan85836c22014-07-09 20:26:25 +1000110static void lpc47n227_enable_serial(pnp_devfn_t dev, u16 iobase)
Stefan Reinauer55426df2010-01-17 13:50:17 +0000111{
Uwe Hermannb69cb5a2010-10-26 22:46:43 +0000112 /*
113 * NOTE: Cannot use pnp_set_XXX() here because they assume chip
114 * support for logical devices, which the LPC47N227 doesn't have.
115 */
Stefan Reinauer55426df2010-01-17 13:50:17 +0000116 pnp_enter_conf_state(dev);
117 lpc47n227_pnp_set_enable(dev, 0);
118 lpc47n227_pnp_set_iobase(dev, iobase);
119 lpc47n227_pnp_set_enable(dev, 1);
120 pnp_exit_conf_state(dev);
121}