blob: 21a54c889d05d38ee06728684388a97f6c6e281d [file] [log] [blame]
Felix Held3f3eca92020-01-23 17:12:32 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer55426df2010-01-17 13:50:17 +00002
3/* Pre-RAM driver for SMSC LPC47N227 Super I/O chip. */
4
Stefan Reinauer24d1d4b2013-03-21 11:51:41 -07005#include <arch/io.h>
Elyes HAOUAScd4fe0f2019-03-29 17:12:15 +01006#include <assert.h>
Kyösti Mälkki3855c012019-03-03 08:45:19 +02007#include <device/pnp_ops.h>
Elyes HAOUAScd4fe0f2019-03-29 17:12:15 +01008
Stefan Reinauer55426df2010-01-17 13:50:17 +00009#include "lpc47n227.h"
10
Antonello Dettori6321d7c2016-03-07 01:59:48 +000011void pnp_enter_conf_state(pnp_devfn_t dev)
Stefan Reinauer55426df2010-01-17 13:50:17 +000012{
Uwe Hermanna69d9782010-11-15 19:35:14 +000013 u16 port = dev >> 8;
Stefan Reinauer55426df2010-01-17 13:50:17 +000014 outb(0x55, port);
15}
16
Antonello Dettori6321d7c2016-03-07 01:59:48 +000017void pnp_exit_conf_state(pnp_devfn_t dev)
Stefan Reinauer55426df2010-01-17 13:50:17 +000018{
Uwe Hermanna69d9782010-11-15 19:35:14 +000019 u16 port = dev >> 8;
Stefan Reinauer55426df2010-01-17 13:50:17 +000020 outb(0xaa, port);
21}
22
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000023/**
24 * Program the base I/O port for the specified logical device.
25 *
26 * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number.
27 * @param iobase Base I/O port for the logical device.
28 */
Edward O'Callaghan85836c22014-07-09 20:26:25 +100029static void lpc47n227_pnp_set_iobase(pnp_devfn_t dev, u16 iobase)
Stefan Reinauer55426df2010-01-17 13:50:17 +000030{
Uwe Hermanna69d9782010-11-15 19:35:14 +000031 /* LPC47N227 requires base ports to be a multiple of 4. */
Patrick Georgid6350682012-05-18 12:47:02 +020032 /* it's not very useful to do an ASSERT here: if it trips,
33 * there's no console to report it.
Stefan Reinauer55426df2010-01-17 13:50:17 +000034 ASSERT(!(iobase & 0x3));
Patrick Georgid6350682012-05-18 12:47:02 +020035 */
Stefan Reinauer55426df2010-01-17 13:50:17 +000036
37 switch (dev & 0xFF) {
38 case LPC47N227_PP:
39 pnp_write_config(dev, 0x23, (iobase >> 2) & 0xff);
40 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000041 case LPC47N227_SP1:
42 pnp_write_config(dev, 0x24, (iobase >> 2) & 0xff);
43 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000044 case LPC47N227_SP2:
45 pnp_write_config(dev, 0x25, (iobase >> 2) & 0xff);
46 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000047 default:
48 break;
49 }
50}
51
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000052/**
53 * Enable or disable the specified logical device.
54 *
55 * Technically, a full disable requires setting the device's base I/O port
56 * below 0x100. We don't do that here, because we don't have access to a data
57 * structure that specifies what the 'real' base port is (when asked to enable
58 * the device). Also the function is used only to disable the device while its
59 * true base port is programmed (see lpc47n227_enable_serial() below).
60 *
61 * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number.
Elyes HAOUAS36c6f9562019-12-05 11:05:19 +010062 * @param enable 0 to disable, anything else to enable.
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000063 */
Edward O'Callaghan85836c22014-07-09 20:26:25 +100064static void lpc47n227_pnp_set_enable(pnp_devfn_t dev, int enable)
Stefan Reinauer55426df2010-01-17 13:50:17 +000065{
Uwe Hermanna69d9782010-11-15 19:35:14 +000066 u8 power_register = 0, power_mask = 0, current_power, new_power;
Stefan Reinauer55426df2010-01-17 13:50:17 +000067
68 switch (dev & 0xFF) {
69 case LPC47N227_PP:
70 power_register = 0x01;
71 power_mask = 0x04;
72 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000073 case LPC47N227_SP1:
74 power_register = 0x02;
75 power_mask = 0x08;
76 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000077 case LPC47N227_SP2:
78 power_register = 0x02;
79 power_mask = 0x80;
80 break;
Stefan Reinauer55426df2010-01-17 13:50:17 +000081 default:
82 return;
83 }
84
85 current_power = pnp_read_config(dev, power_register);
Uwe Hermanna69d9782010-11-15 19:35:14 +000086 new_power = current_power & ~power_mask; /* Disable by default. */
Stefan Reinauer55426df2010-01-17 13:50:17 +000087 if (enable)
Uwe Hermanna69d9782010-11-15 19:35:14 +000088 new_power |= power_mask; /* Enable. */
Stefan Reinauer55426df2010-01-17 13:50:17 +000089 pnp_write_config(dev, power_register, new_power);
90}
91
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000092/**
93 * Configure the base I/O port of the specified serial device and enable the
94 * serial device.
95 *
96 * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number.
97 * @param iobase Processor I/O port address to assign to this serial device.
98 */
Antonello Dettori6321d7c2016-03-07 01:59:48 +000099void lpc47n227_enable_serial(pnp_devfn_t dev, u16 iobase)
Stefan Reinauer55426df2010-01-17 13:50:17 +0000100{
Uwe Hermannb69cb5a2010-10-26 22:46:43 +0000101 /*
102 * NOTE: Cannot use pnp_set_XXX() here because they assume chip
103 * support for logical devices, which the LPC47N227 doesn't have.
104 */
Stefan Reinauer55426df2010-01-17 13:50:17 +0000105 pnp_enter_conf_state(dev);
106 lpc47n227_pnp_set_enable(dev, 0);
107 lpc47n227_pnp_set_iobase(dev, iobase);
108 lpc47n227_pnp_set_enable(dev, 1);
109 pnp_exit_conf_state(dev);
110}