blob: 14589450d233d24450e272ecf400ea444580f0cb [file] [log] [blame]
Subrata Banik7bc4dc52018-05-17 18:40:32 +05301/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2018 Intel 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; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <arch/io.h>
17#include <device/device.h>
18#include <device/pci.h>
19#include <device/pci_def.h>
20#include <intelblocks/pcr.h>
21#include <intelblocks/tco.h>
22#include <soc/iomap.h>
23#include <soc/pci_devs.h>
24#include <soc/pcr_ids.h>
25#include <soc/pm.h>
26#include <soc/smbus.h>
27
28#define PCR_DMI_TCOBASE 0x2778
29/* Enable TCO I/O range decode. */
30#define TCOEN (1 << 1)
31
32/* SMBUS TCO base address. */
33#define TCOBASE 0x50
34#define TCOCTL 0x54
35#define TCO_BASE_EN (1 << 8)
36
37/* Get base address of TCO I/O registers. */
38static uint16_t tco_get_bar(void)
39{
40 return TCO_BASE_ADDRESS;
41}
42
43uint16_t tco_read_reg(uint16_t tco_reg)
44{
45 uint16_t tcobase;
46
47 tcobase = tco_get_bar();
48
49 return inw(tcobase + tco_reg);
50}
51
52void tco_write_reg(uint16_t tco_reg, uint16_t value)
53{
54 uint16_t tcobase;
55
56 tcobase = tco_get_bar();
57
58 outw(value, tcobase + tco_reg);
59}
60
61void tco_lockdown(void)
62{
63 uint16_t tcocnt;
64
65 /* TCO Lock down */
66 tcocnt = tco_read_reg(TCO1_CNT);
67 tcocnt |= TCO_LOCK;
68 tco_write_reg(TCO1_CNT, tcocnt);
69}
70
71uint32_t tco_reset_status(void)
72{
73 uint16_t tco1_sts;
74 uint16_t tco2_sts;
75
76 /* TCO Status 2 register */
77 tco2_sts = tco_read_reg(TCO2_STS);
78 tco2_sts |= TCO_STS_SECOND_TO;
79 tco_write_reg(TCO2_STS, tco2_sts);
80
81 /* TCO Status 1 register */
82 tco1_sts = tco_read_reg(TCO1_STS);
83
84 return (tco2_sts << 16) | tco1_sts;
85}
86
87/* Stop TCO timer */
88static void tco_timer_disable(void)
89{
90 uint16_t tcocnt;
91
92 /* Program TCO timer halt */
93 tcocnt = tco_read_reg(TCO1_CNT);
94 tcocnt |= TCO_TMR_HLT;
95 tco_write_reg(TCO1_CNT, tcocnt);
96}
97
98/* Enable TCO BAR using SMBUS TCO base to access TCO related register */
99static void tco_enable_bar(void)
100{
101 uint32_t reg32;
102 uint16_t tcobase;
103#if defined(__SIMPLE_DEVICE__)
104 int devfn = PCH_DEVFN_SMBUS;
105 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
106#else
107 struct device *dev;
108 dev = PCH_DEV_SMBUS;
109#endif
110
111 /* Disable TCO in SMBUS Device first before changing Base Address */
112 reg32 = pci_read_config32(dev, TCOCTL);
113 reg32 &= ~TCO_BASE_EN;
114 pci_write_config32(dev, TCOCTL, reg32);
115
116 /* Program TCO Base */
117 tcobase = tco_get_bar();
118 pci_write_config32(dev, TCOBASE, tcobase);
119
120 /* Enable TCO in SMBUS */
121 pci_write_config32(dev, TCOCTL, reg32 | TCO_BASE_EN);
122
123 /*
124 * Program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1]
125 */
126 pcr_write32(PID_DMI, PCR_DMI_TCOBASE, tcobase | TCOEN);
127}
128
129/*
130 * Enable TCO BAR using SMBUS TCO base to access TCO related register
131 * also disable the timer.
132 */
133void tco_configure(void)
134{
135 if (IS_ENABLED(CONFIG_SOC_INTEL_COMMON_BLOCK_TCO_ENABLE_THROUGH_SMBUS))
136 tco_enable_bar();
137
138 tco_timer_disable();
139}