Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 1 | /* |
Stefan Reinauer | 7e61e45 | 2008-01-18 10:35:56 +0000 | [diff] [blame] | 2 | * This file is part of the coreboot project. |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2005 Digital Design Corporation |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 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 Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 15 | */ |
| 16 | |
Uwe Hermann | d82baa1 | 2006-12-05 14:13:10 +0000 | [diff] [blame] | 17 | /* Pre-RAM driver for SMSC LPC47N217 Super I/O chip. */ |
| 18 | |
Stefan Reinauer | 24d1d4b | 2013-03-21 11:51:41 -0700 | [diff] [blame] | 19 | #include <arch/io.h> |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 20 | #include <assert.h> |
| 21 | #include "lpc47n217.h" |
| 22 | |
Edward O'Callaghan | 85836c2 | 2014-07-09 20:26:25 +1000 | [diff] [blame] | 23 | static void pnp_enter_conf_state(pnp_devfn_t dev) |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 24 | { |
Uwe Hermann | a69d978 | 2010-11-15 19:35:14 +0000 | [diff] [blame] | 25 | u16 port = dev >> 8; |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 26 | outb(0x55, port); |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 27 | } |
| 28 | |
Edward O'Callaghan | 85836c2 | 2014-07-09 20:26:25 +1000 | [diff] [blame] | 29 | static void pnp_exit_conf_state(pnp_devfn_t dev) |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 30 | { |
Uwe Hermann | a69d978 | 2010-11-15 19:35:14 +0000 | [diff] [blame] | 31 | u16 port = dev >> 8; |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 32 | outb(0xaa, port); |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 33 | } |
| 34 | |
Uwe Hermann | b69cb5a | 2010-10-26 22:46:43 +0000 | [diff] [blame] | 35 | /** |
| 36 | * Program the base I/O port for the specified logical device. |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 37 | * |
Uwe Hermann | b69cb5a | 2010-10-26 22:46:43 +0000 | [diff] [blame] | 38 | * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number. |
| 39 | * @param iobase Base I/O port for the logical device. |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 40 | */ |
Edward O'Callaghan | 85836c2 | 2014-07-09 20:26:25 +1000 | [diff] [blame] | 41 | static void lpc47n217_pnp_set_iobase(pnp_devfn_t dev, u16 iobase) |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 42 | { |
Uwe Hermann | a69d978 | 2010-11-15 19:35:14 +0000 | [diff] [blame] | 43 | /* LPC47N217 requires base ports to be a multiple of 4. */ |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 44 | ASSERT(!(iobase & 0x3)); |
| 45 | |
| 46 | switch(dev & 0xFF) { |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 47 | case LPC47N217_PP: |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 48 | pnp_write_config(dev, 0x23, (iobase >> 2) & 0xff); |
| 49 | break; |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 50 | case LPC47N217_SP1: |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 51 | pnp_write_config(dev, 0x24, (iobase >> 2) & 0xff); |
| 52 | break; |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 53 | case LPC47N217_SP2: |
| 54 | pnp_write_config(dev, 0x25, (iobase >> 2) & 0xff); |
| 55 | break; |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 56 | default: |
| 57 | break; |
| 58 | } |
| 59 | } |
| 60 | |
Uwe Hermann | b69cb5a | 2010-10-26 22:46:43 +0000 | [diff] [blame] | 61 | /** |
| 62 | * Enable or disable the specified logical device. |
| 63 | * |
| 64 | * Technically, a full disable requires setting the device's base I/O port |
| 65 | * below 0x100. We don't do that here, because we don't have access to a data |
| 66 | * structure that specifies what the 'real' base port is (when asked to enable |
| 67 | * the device). Also the function is used only to disable the device while its |
| 68 | * true base port is programmed (see lpc47n217_enable_serial() below). |
| 69 | * |
| 70 | * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number. |
| 71 | * @param enable 0 to disable, anythig else to enable. |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 72 | */ |
Edward O'Callaghan | 85836c2 | 2014-07-09 20:26:25 +1000 | [diff] [blame] | 73 | static void lpc47n217_pnp_set_enable(pnp_devfn_t dev, int enable) |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 74 | { |
Uwe Hermann | a69d978 | 2010-11-15 19:35:14 +0000 | [diff] [blame] | 75 | u8 power_register = 0, power_mask = 0, current_power, new_power; |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 76 | |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 77 | switch(dev & 0xFF) { |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 78 | case LPC47N217_PP: |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 79 | power_register = 0x01; |
| 80 | power_mask = 0x04; |
| 81 | break; |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 82 | case LPC47N217_SP1: |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 83 | power_register = 0x02; |
| 84 | power_mask = 0x08; |
| 85 | break; |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 86 | case LPC47N217_SP2: |
| 87 | power_register = 0x02; |
| 88 | power_mask = 0x80; |
| 89 | break; |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 90 | default: |
| 91 | return; |
| 92 | } |
| 93 | |
| 94 | current_power = pnp_read_config(dev, power_register); |
Uwe Hermann | a69d978 | 2010-11-15 19:35:14 +0000 | [diff] [blame] | 95 | new_power = current_power & ~power_mask; /* Disable by default. */ |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 96 | if (enable) |
Uwe Hermann | a69d978 | 2010-11-15 19:35:14 +0000 | [diff] [blame] | 97 | new_power |= power_mask; /* Enable. */ |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 98 | pnp_write_config(dev, power_register, new_power); |
| 99 | } |
| 100 | |
Uwe Hermann | b69cb5a | 2010-10-26 22:46:43 +0000 | [diff] [blame] | 101 | /** |
| 102 | * Configure the base I/O port of the specified serial device and enable the |
| 103 | * serial device. |
| 104 | * |
| 105 | * @param dev High 8 bits = Super I/O port, low 8 bits = logical device number. |
| 106 | * @param iobase Processor I/O port address to assign to this serial device. |
Zheng Bao | 9db833b | 2009-12-28 09:59:44 +0000 | [diff] [blame] | 107 | */ |
Antonello Dettori | bc839fb | 2016-03-03 16:25:35 +0000 | [diff] [blame] | 108 | void lpc47n217_enable_serial(pnp_devfn_t dev, u16 iobase) |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 109 | { |
Uwe Hermann | b69cb5a | 2010-10-26 22:46:43 +0000 | [diff] [blame] | 110 | /* |
| 111 | * NOTE: Cannot use pnp_set_XXX() here because they assume chip |
| 112 | * support for logical devices, which the LPC47N217 doesn't have. |
| 113 | */ |
Stefan Reinauer | eca92fb | 2006-08-23 14:28:37 +0000 | [diff] [blame] | 114 | pnp_enter_conf_state(dev); |
| 115 | lpc47n217_pnp_set_enable(dev, 0); |
| 116 | lpc47n217_pnp_set_iobase(dev, iobase); |
| 117 | lpc47n217_pnp_set_enable(dev, 1); |
| 118 | pnp_exit_conf_state(dev); |
| 119 | } |