blob: 12b176c094de9e964f1efb6ed4ec7ea403c9c76a [file] [log] [blame]
Angel Pons0612b272020-04-05 15:46:56 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Subrata Banik7bc4dc52018-05-17 18:40:32 +05302
Angel Pons24f46232021-04-17 12:08:15 +02003#define __SIMPLE_DEVICE__
4
Subrata Banik7bc4dc52018-05-17 18:40:32 +05305#include <arch/io.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02006#include <device/pci_ops.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +05307#include <device/device.h>
8#include <device/pci.h>
9#include <device/pci_def.h>
Subrata Banik211be9c2022-04-13 12:13:09 +053010#include <intelblocks/gpmr.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +053011#include <intelblocks/pcr.h>
Michael Niewöhner2bd2be52020-03-03 20:47:01 +010012#include <intelblocks/pmclib.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +053013#include <intelblocks/tco.h>
14#include <soc/iomap.h>
15#include <soc/pci_devs.h>
16#include <soc/pcr_ids.h>
17#include <soc/pm.h>
18#include <soc/smbus.h>
19
Subrata Banik7bc4dc52018-05-17 18:40:32 +053020/* SMBUS TCO base address. */
21#define TCOBASE 0x50
22#define TCOCTL 0x54
23#define TCO_BASE_EN (1 << 8)
Michael Niewöhner3c20cba2019-09-22 13:27:20 +020024#define TCO_BASE_LOCK (1 << 0)
Subrata Banik7bc4dc52018-05-17 18:40:32 +053025
26/* Get base address of TCO I/O registers. */
27static uint16_t tco_get_bar(void)
28{
29 return TCO_BASE_ADDRESS;
30}
31
32uint16_t tco_read_reg(uint16_t tco_reg)
33{
34 uint16_t tcobase;
35
36 tcobase = tco_get_bar();
37
38 return inw(tcobase + tco_reg);
39}
40
41void tco_write_reg(uint16_t tco_reg, uint16_t value)
42{
43 uint16_t tcobase;
44
45 tcobase = tco_get_bar();
46
47 outw(value, tcobase + tco_reg);
48}
49
50void tco_lockdown(void)
51{
52 uint16_t tcocnt;
Michael Niewöhner3c20cba2019-09-22 13:27:20 +020053 const pci_devfn_t dev = PCH_DEV_SMBUS;
54
55 /* TCO base address lockdown */
56 pci_or_config32(dev, TCOCTL, TCO_BASE_LOCK);
Subrata Banik7bc4dc52018-05-17 18:40:32 +053057
58 /* TCO Lock down */
59 tcocnt = tco_read_reg(TCO1_CNT);
60 tcocnt |= TCO_LOCK;
61 tco_write_reg(TCO1_CNT, tcocnt);
62}
63
64uint32_t tco_reset_status(void)
65{
66 uint16_t tco1_sts;
67 uint16_t tco2_sts;
68
Subrata Banik7bc4dc52018-05-17 18:40:32 +053069 /* TCO Status 1 register */
70 tco1_sts = tco_read_reg(TCO1_STS);
Michael Niewöhner04b02062020-03-03 18:33:00 +010071 tco_write_reg(TCO1_STS, tco1_sts);
72
73 /* TCO Status 2 register */
74 tco2_sts = tco_read_reg(TCO2_STS);
Kyösti Mälkki307320c2022-11-21 17:27:07 +020075 tco_write_reg(TCO2_STS, tco2_sts | TCO2_STS_SECOND_TO);
Subrata Banik7bc4dc52018-05-17 18:40:32 +053076
77 return (tco2_sts << 16) | tco1_sts;
78}
79
80/* Stop TCO timer */
81static void tco_timer_disable(void)
82{
83 uint16_t tcocnt;
84
85 /* Program TCO timer halt */
86 tcocnt = tco_read_reg(TCO1_CNT);
87 tcocnt |= TCO_TMR_HLT;
88 tco_write_reg(TCO1_CNT, tcocnt);
89}
90
Michael Niewöhner2bd2be52020-03-03 20:47:01 +010091/* Enable and initialize TCO intruder SMI */
92static void tco_intruder_smi_enable(void)
93{
94 uint16_t tcocnt;
95
96 /* Make TCO issue an SMI on INTRD_DET assertion */
97 tcocnt = tco_read_reg(TCO2_CNT);
98 tcocnt &= ~TCO_INTRD_SEL_MASK;
99 tcocnt |= TCO_INTRD_SEL_SMI;
100 tco_write_reg(TCO2_CNT, tcocnt);
101}
102
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530103/* Enable TCO BAR using SMBUS TCO base to access TCO related register */
104static void tco_enable_bar(void)
105{
106 uint32_t reg32;
107 uint16_t tcobase;
Angel Pons24f46232021-04-17 12:08:15 +0200108 const pci_devfn_t dev = PCH_DEV_SMBUS;
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530109
110 /* Disable TCO in SMBUS Device first before changing Base Address */
111 reg32 = pci_read_config32(dev, TCOCTL);
112 reg32 &= ~TCO_BASE_EN;
113 pci_write_config32(dev, TCOCTL, reg32);
114
115 /* Program TCO Base */
116 tcobase = tco_get_bar();
117 pci_write_config32(dev, TCOBASE, tcobase);
118
119 /* Enable TCO in SMBUS */
120 pci_write_config32(dev, TCOCTL, reg32 | TCO_BASE_EN);
121
Subrata Banik211be9c2022-04-13 12:13:09 +0530122 /* Program TCO Base Address */
123 gpmr_write32(GPMR_TCOBASE, tcobase | GPMR_TCOEN);
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530124}
125
126/*
127 * Enable TCO BAR using SMBUS TCO base to access TCO related register
128 * also disable the timer.
129 */
130void tco_configure(void)
131{
Julius Wernercd49cce2019-03-05 16:53:33 -0800132 if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCO_ENABLE_THROUGH_SMBUS))
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530133 tco_enable_bar();
134
135 tco_timer_disable();
Michael Niewöhner2bd2be52020-03-03 20:47:01 +0100136
137 /* Enable intruder interrupt if TCO interrupts are enabled*/
138 if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE))
139 tco_intruder_smi_enable();
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530140}