blob: 1aa42ef47b51fbef36390a1180a3d39d9f7420dc [file] [log] [blame]
Angel Ponsae593872020-04-04 18:50:57 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Martin Roth5c354b92019-04-22 14:55:16 -06002
Raul E Rangel34fb9392020-06-11 16:57:23 -06003#include <acpi/acpigen.h>
Raul E Rangel34fb9392020-06-11 16:57:23 -06004#include <console/console.h>
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -06005#include <commonlib/helpers.h>
Julius Werner55009af2019-12-02 22:03:27 -08006#include <device/mmio.h>
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -06007#include <amdblocks/gpio_banks.h>
8#include <amdblocks/acpimmio.h>
Martin Roth5c354b92019-04-22 14:55:16 -06009#include <soc/southbridge.h>
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -060010#include <soc/gpio.h>
Felix Held9412b3e2020-06-18 15:54:43 +020011#include <soc/uart.h>
Felix Held2e800032020-09-12 01:28:46 +020012#include <types.h>
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -060013
14static const struct _uart_info {
15 uintptr_t base;
16 struct soc_amd_gpio mux[2];
17} uart_info[] = {
18 [0] = { APU_UART0_BASE, {
19 PAD_NF(GPIO_138, UART0_TXD, PULL_NONE),
20 PAD_NF(GPIO_136, UART0_RXD, PULL_NONE),
21 } },
22 [1] = { APU_UART1_BASE, {
23 PAD_NF(GPIO_143, UART1_TXD, PULL_NONE),
24 PAD_NF(GPIO_141, UART1_RXD, PULL_NONE),
25 } },
26 [2] = { APU_UART2_BASE, {
27 PAD_NF(GPIO_137, UART2_TXD, PULL_NONE),
28 PAD_NF(GPIO_135, UART2_RXD, PULL_NONE),
29 } },
30 [3] = { APU_UART3_BASE, {
31 PAD_NF(GPIO_140, UART3_TXD, PULL_NONE),
32 PAD_NF(GPIO_142, UART3_RXD, PULL_NONE),
33 } },
34};
Martin Roth5c354b92019-04-22 14:55:16 -060035
Felix Held83951652020-09-11 14:53:03 +020036uintptr_t get_uart_base(unsigned int idx)
Martin Roth5c354b92019-04-22 14:55:16 -060037{
Felix Held83951652020-09-11 14:53:03 +020038 if (idx >= ARRAY_SIZE(uart_info))
Martin Roth5c354b92019-04-22 14:55:16 -060039 return 0;
40
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -060041 return uart_info[idx].base;
42}
43
Rob Barnes28cb14b2020-01-30 10:54:28 -070044static bool get_uart_idx(uintptr_t base, unsigned int *idx)
45{
46 for (unsigned int i = 0; i < ARRAY_SIZE(uart_info); i++) {
47 if (base == uart_info[i].base) {
48 *idx = i;
49 return true;
50 }
51 }
52
53 return false;
54}
55
Raul E Rangel4f5936b2020-06-11 16:27:49 -060056void clear_uart_legacy_config(void)
57{
Rob Barnes28cb14b2020-01-30 10:54:28 -070058 write16((void *)FCH_LEGACY_UART_DECODE, 0);
59}
60
61void set_uart_legacy_config(unsigned int uart_idx, unsigned int range_idx)
62{
63 uint16_t uart_legacy_decode;
64 uint8_t uart_map_offset;
65
66 if (uart_idx >= ARRAY_SIZE(uart_info) || range_idx >= ARRAY_SIZE(uart_info))
67 return;
68
69 uart_legacy_decode = read16((void *)FCH_LEGACY_UART_DECODE);
70 /* Map uart_idx to io range_idx */
71 uart_map_offset = range_idx * FCH_LEGACY_UART_MAP_SIZE + FCH_LEGACY_UART_MAP_SHIFT;
72 uart_legacy_decode &= ~(FCH_LEGACY_UART_MAP_MASK << uart_map_offset);
73 uart_legacy_decode |= uart_idx << uart_map_offset;
74 /* Enable io range */
75 uart_legacy_decode |= 1 << range_idx;
76 write16((void *)FCH_LEGACY_UART_DECODE, uart_legacy_decode);
77}
78
79static void enable_uart_legacy_decode(uintptr_t base)
80{
81 unsigned int idx;
82 const uint8_t range_idx[ARRAY_SIZE(uart_info)] = {
83 FCH_LEGACY_UART_RANGE_3F8,
84 FCH_LEGACY_UART_RANGE_2F8,
85 FCH_LEGACY_UART_RANGE_3E8,
86 FCH_LEGACY_UART_RANGE_2E8,
87 };
88
89 if (get_uart_idx(base, &idx)) {
90 set_uart_legacy_config(idx, range_idx[idx]);
91 }
Raul E Rangel4f5936b2020-06-11 16:27:49 -060092}
93
Felix Held83951652020-09-11 14:53:03 +020094void set_uart_config(unsigned int idx)
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -060095{
96 uint32_t uart_ctrl;
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -060097
Felix Held83951652020-09-11 14:53:03 +020098 if (idx >= ARRAY_SIZE(uart_info))
Marshall Dawsonc0b8d0d2019-06-20 10:29:29 -060099 return;
100
101 program_gpios(uart_info[idx].mux, 2);
102
103 if (CONFIG(PICASSO_UART_1_8MZ)) {
104 uart_ctrl = sm_pci_read32(SMB_UART_CONFIG);
105 uart_ctrl |= 1 << (SMB_UART_1_8M_SHIFT + idx);
106 sm_pci_write32(SMB_UART_CONFIG, uart_ctrl);
107 }
108
Martin Roth5c354b92019-04-22 14:55:16 -0600109}
110
Furquan Shaikhb07e2622020-06-03 16:50:32 -0700111static const char *uart_acpi_name(const struct device *dev)
112{
113 switch (dev->path.mmio.addr) {
114 case APU_UART0_BASE:
115 return "FUR0";
116 case APU_UART1_BASE:
117 return "FUR1";
118 case APU_UART2_BASE:
119 return "FUR2";
120 case APU_UART3_BASE:
121 return "FUR3";
122 default:
123 return NULL;
124 }
125}
126
Raul E Rangel34fb9392020-06-11 16:57:23 -0600127/* Even though this is called enable, it gets called for both enabled and disabled devices. */
128static void uart_enable(struct device *dev)
129{
Felix Held26170732020-09-12 01:30:25 +0200130 unsigned int dev_id;
Raul E Rangel34fb9392020-06-11 16:57:23 -0600131
132 switch (dev->path.mmio.addr) {
133 case APU_UART0_BASE:
134 dev_id = FCH_AOAC_DEV_UART0;
135 break;
136 case APU_UART1_BASE:
137 dev_id = FCH_AOAC_DEV_UART1;
138 break;
139 case APU_UART2_BASE:
140 dev_id = FCH_AOAC_DEV_UART2;
141 break;
142 case APU_UART3_BASE:
143 dev_id = FCH_AOAC_DEV_UART3;
144 break;
145 default:
146 printk(BIOS_ERR, "%s: Unknown device: %s\n", __func__, dev_path(dev));
147 return;
148 }
149
150 if (dev->enabled) {
151 power_on_aoac_device(dev_id);
152 wait_for_aoac_enabled(dev_id);
Rob Barnes28cb14b2020-01-30 10:54:28 -0700153 if (CONFIG(PICASSO_UART_LEGACY))
154 enable_uart_legacy_decode(dev->path.mmio.addr);
Raul E Rangel34fb9392020-06-11 16:57:23 -0600155 } else {
156 power_off_aoac_device(dev_id);
157 }
158}
159
160/* This gets called for both enabled and disabled devices. */
161static void uart_inject_ssdt(const struct device *dev)
162{
163 acpigen_write_scope(acpi_device_path(dev));
164
165 acpigen_write_STA(acpi_device_status(dev));
166
167 acpigen_pop_len(); /* Scope */
168}
169
Furquan Shaikhb07e2622020-06-03 16:50:32 -0700170struct device_operations picasso_uart_mmio_ops = {
171 .read_resources = noop_read_resources,
172 .set_resources = noop_set_resources,
173 .scan_bus = scan_static_bus,
174 .acpi_name = uart_acpi_name,
Raul E Rangel34fb9392020-06-11 16:57:23 -0600175 .enable = uart_enable,
176 .acpi_fill_ssdt = uart_inject_ssdt,
Furquan Shaikhb07e2622020-06-03 16:50:32 -0700177};