blob: 2c0b760481fcb6de2f5b75f6cf3eb64b23f37312 [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>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020017#include <device/pci_ops.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +053018#include <device/device.h>
19#include <device/pci.h>
20#include <device/pci_def.h>
21#include <intelblocks/pcr.h>
Michael Niewöhner2bd2be52020-03-03 20:47:01 +010022#include <intelblocks/pmclib.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +053023#include <intelblocks/tco.h>
24#include <soc/iomap.h>
25#include <soc/pci_devs.h>
26#include <soc/pcr_ids.h>
27#include <soc/pm.h>
28#include <soc/smbus.h>
29
30#define PCR_DMI_TCOBASE 0x2778
31/* Enable TCO I/O range decode. */
32#define TCOEN (1 << 1)
33
34/* SMBUS TCO base address. */
35#define TCOBASE 0x50
36#define TCOCTL 0x54
37#define TCO_BASE_EN (1 << 8)
38
39/* Get base address of TCO I/O registers. */
40static uint16_t tco_get_bar(void)
41{
42 return TCO_BASE_ADDRESS;
43}
44
45uint16_t tco_read_reg(uint16_t tco_reg)
46{
47 uint16_t tcobase;
48
49 tcobase = tco_get_bar();
50
51 return inw(tcobase + tco_reg);
52}
53
54void tco_write_reg(uint16_t tco_reg, uint16_t value)
55{
56 uint16_t tcobase;
57
58 tcobase = tco_get_bar();
59
60 outw(value, tcobase + tco_reg);
61}
62
63void tco_lockdown(void)
64{
65 uint16_t tcocnt;
66
67 /* TCO Lock down */
68 tcocnt = tco_read_reg(TCO1_CNT);
69 tcocnt |= TCO_LOCK;
70 tco_write_reg(TCO1_CNT, tcocnt);
71}
72
73uint32_t tco_reset_status(void)
74{
75 uint16_t tco1_sts;
76 uint16_t tco2_sts;
77
Subrata Banik7bc4dc52018-05-17 18:40:32 +053078 /* TCO Status 1 register */
79 tco1_sts = tco_read_reg(TCO1_STS);
Michael Niewöhner04b02062020-03-03 18:33:00 +010080 tco_write_reg(TCO1_STS, tco1_sts);
81
82 /* TCO Status 2 register */
83 tco2_sts = tco_read_reg(TCO2_STS);
84 tco_write_reg(TCO2_STS, tco2_sts | TCO_STS_SECOND_TO);
Subrata Banik7bc4dc52018-05-17 18:40:32 +053085
86 return (tco2_sts << 16) | tco1_sts;
87}
88
89/* Stop TCO timer */
90static void tco_timer_disable(void)
91{
92 uint16_t tcocnt;
93
94 /* Program TCO timer halt */
95 tcocnt = tco_read_reg(TCO1_CNT);
96 tcocnt |= TCO_TMR_HLT;
97 tco_write_reg(TCO1_CNT, tcocnt);
98}
99
Michael Niewöhner2bd2be52020-03-03 20:47:01 +0100100/* Enable and initialize TCO intruder SMI */
101static void tco_intruder_smi_enable(void)
102{
103 uint16_t tcocnt;
104
105 /* Make TCO issue an SMI on INTRD_DET assertion */
106 tcocnt = tco_read_reg(TCO2_CNT);
107 tcocnt &= ~TCO_INTRD_SEL_MASK;
108 tcocnt |= TCO_INTRD_SEL_SMI;
109 tco_write_reg(TCO2_CNT, tcocnt);
110}
111
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530112/* Enable TCO BAR using SMBUS TCO base to access TCO related register */
113static void tco_enable_bar(void)
114{
115 uint32_t reg32;
116 uint16_t tcobase;
117#if defined(__SIMPLE_DEVICE__)
118 int devfn = PCH_DEVFN_SMBUS;
119 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
120#else
121 struct device *dev;
122 dev = PCH_DEV_SMBUS;
123#endif
124
125 /* Disable TCO in SMBUS Device first before changing Base Address */
126 reg32 = pci_read_config32(dev, TCOCTL);
127 reg32 &= ~TCO_BASE_EN;
128 pci_write_config32(dev, TCOCTL, reg32);
129
130 /* Program TCO Base */
131 tcobase = tco_get_bar();
132 pci_write_config32(dev, TCOBASE, tcobase);
133
134 /* Enable TCO in SMBUS */
135 pci_write_config32(dev, TCOCTL, reg32 | TCO_BASE_EN);
136
137 /*
138 * Program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1]
139 */
140 pcr_write32(PID_DMI, PCR_DMI_TCOBASE, tcobase | TCOEN);
141}
142
143/*
144 * Enable TCO BAR using SMBUS TCO base to access TCO related register
145 * also disable the timer.
146 */
147void tco_configure(void)
148{
Julius Wernercd49cce2019-03-05 16:53:33 -0800149 if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCO_ENABLE_THROUGH_SMBUS))
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530150 tco_enable_bar();
151
152 tco_timer_disable();
Michael Niewöhner2bd2be52020-03-03 20:47:01 +0100153
154 /* Enable intruder interrupt if TCO interrupts are enabled*/
155 if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE))
156 tco_intruder_smi_enable();
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530157}