blob: 1a215eb69d9c05147027abeb446a9dd44c04c36e [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>
22#include <intelblocks/tco.h>
23#include <soc/iomap.h>
24#include <soc/pci_devs.h>
25#include <soc/pcr_ids.h>
26#include <soc/pm.h>
27#include <soc/smbus.h>
28
29#define PCR_DMI_TCOBASE 0x2778
30/* Enable TCO I/O range decode. */
31#define TCOEN (1 << 1)
32
33/* SMBUS TCO base address. */
34#define TCOBASE 0x50
35#define TCOCTL 0x54
36#define TCO_BASE_EN (1 << 8)
37
38/* Get base address of TCO I/O registers. */
39static uint16_t tco_get_bar(void)
40{
41 return TCO_BASE_ADDRESS;
42}
43
44uint16_t tco_read_reg(uint16_t tco_reg)
45{
46 uint16_t tcobase;
47
48 tcobase = tco_get_bar();
49
50 return inw(tcobase + tco_reg);
51}
52
53void tco_write_reg(uint16_t tco_reg, uint16_t value)
54{
55 uint16_t tcobase;
56
57 tcobase = tco_get_bar();
58
59 outw(value, tcobase + tco_reg);
60}
61
62void tco_lockdown(void)
63{
64 uint16_t tcocnt;
65
66 /* TCO Lock down */
67 tcocnt = tco_read_reg(TCO1_CNT);
68 tcocnt |= TCO_LOCK;
69 tco_write_reg(TCO1_CNT, tcocnt);
70}
71
72uint32_t tco_reset_status(void)
73{
74 uint16_t tco1_sts;
75 uint16_t tco2_sts;
76
77 /* TCO Status 2 register */
78 tco2_sts = tco_read_reg(TCO2_STS);
79 tco2_sts |= TCO_STS_SECOND_TO;
80 tco_write_reg(TCO2_STS, tco2_sts);
81
82 /* TCO Status 1 register */
83 tco1_sts = tco_read_reg(TCO1_STS);
84
85 return (tco2_sts << 16) | tco1_sts;
86}
87
88/* Stop TCO timer */
89static void tco_timer_disable(void)
90{
91 uint16_t tcocnt;
92
93 /* Program TCO timer halt */
94 tcocnt = tco_read_reg(TCO1_CNT);
95 tcocnt |= TCO_TMR_HLT;
96 tco_write_reg(TCO1_CNT, tcocnt);
97}
98
99/* Enable TCO BAR using SMBUS TCO base to access TCO related register */
100static void tco_enable_bar(void)
101{
102 uint32_t reg32;
103 uint16_t tcobase;
104#if defined(__SIMPLE_DEVICE__)
105 int devfn = PCH_DEVFN_SMBUS;
106 pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
107#else
108 struct device *dev;
109 dev = PCH_DEV_SMBUS;
110#endif
111
112 /* Disable TCO in SMBUS Device first before changing Base Address */
113 reg32 = pci_read_config32(dev, TCOCTL);
114 reg32 &= ~TCO_BASE_EN;
115 pci_write_config32(dev, TCOCTL, reg32);
116
117 /* Program TCO Base */
118 tcobase = tco_get_bar();
119 pci_write_config32(dev, TCOBASE, tcobase);
120
121 /* Enable TCO in SMBUS */
122 pci_write_config32(dev, TCOCTL, reg32 | TCO_BASE_EN);
123
124 /*
125 * Program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1]
126 */
127 pcr_write32(PID_DMI, PCR_DMI_TCOBASE, tcobase | TCOEN);
128}
129
130/*
131 * Enable TCO BAR using SMBUS TCO base to access TCO related register
132 * also disable the timer.
133 */
134void tco_configure(void)
135{
Julius Wernercd49cce2019-03-05 16:53:33 -0800136 if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCO_ENABLE_THROUGH_SMBUS))
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530137 tco_enable_bar();
138
139 tco_timer_disable();
140}