blob: 1f1a85c5b378370d3bd68099b2e736bc95183b0f [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>
Subrata Banik211be9c2022-04-13 12:13:09 +05309#include <intelblocks/gpmr.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +053010#include <intelblocks/pcr.h>
Michael Niewöhner2bd2be52020-03-03 20:47:01 +010011#include <intelblocks/pmclib.h>
Subrata Banik7bc4dc52018-05-17 18:40:32 +053012#include <intelblocks/tco.h>
13#include <soc/iomap.h>
14#include <soc/pci_devs.h>
15#include <soc/pcr_ids.h>
16#include <soc/pm.h>
17#include <soc/smbus.h>
18
Subrata Banik7bc4dc52018-05-17 18:40:32 +053019/* SMBUS TCO base address. */
20#define TCOBASE 0x50
21#define TCOCTL 0x54
22#define TCO_BASE_EN (1 << 8)
Michael Niewöhner3c20cba2019-09-22 13:27:20 +020023#define TCO_BASE_LOCK (1 << 0)
Subrata Banik7bc4dc52018-05-17 18:40:32 +053024
25/* Get base address of TCO I/O registers. */
26static uint16_t tco_get_bar(void)
27{
28 return TCO_BASE_ADDRESS;
29}
30
31uint16_t tco_read_reg(uint16_t tco_reg)
32{
33 uint16_t tcobase;
34
35 tcobase = tco_get_bar();
36
37 return inw(tcobase + tco_reg);
38}
39
40void tco_write_reg(uint16_t tco_reg, uint16_t value)
41{
42 uint16_t tcobase;
43
44 tcobase = tco_get_bar();
45
46 outw(value, tcobase + tco_reg);
47}
48
49void tco_lockdown(void)
50{
51 uint16_t tcocnt;
Michael Niewöhner3c20cba2019-09-22 13:27:20 +020052 const pci_devfn_t dev = PCH_DEV_SMBUS;
53
54 /* TCO base address lockdown */
55 pci_or_config32(dev, TCOCTL, TCO_BASE_LOCK);
Subrata Banik7bc4dc52018-05-17 18:40:32 +053056
57 /* TCO Lock down */
58 tcocnt = tco_read_reg(TCO1_CNT);
59 tcocnt |= TCO_LOCK;
60 tco_write_reg(TCO1_CNT, tcocnt);
61}
62
63uint32_t tco_reset_status(void)
64{
65 uint16_t tco1_sts;
66 uint16_t tco2_sts;
67
Subrata Banik7bc4dc52018-05-17 18:40:32 +053068 /* TCO Status 1 register */
69 tco1_sts = tco_read_reg(TCO1_STS);
Michael Niewöhner04b02062020-03-03 18:33:00 +010070 tco_write_reg(TCO1_STS, tco1_sts);
71
72 /* TCO Status 2 register */
73 tco2_sts = tco_read_reg(TCO2_STS);
Kyösti Mälkki307320c2022-11-21 17:27:07 +020074 tco_write_reg(TCO2_STS, tco2_sts | TCO2_STS_SECOND_TO);
Subrata Banik7bc4dc52018-05-17 18:40:32 +053075
76 return (tco2_sts << 16) | tco1_sts;
77}
78
79/* Stop TCO timer */
80static void tco_timer_disable(void)
81{
82 uint16_t tcocnt;
83
84 /* Program TCO timer halt */
85 tcocnt = tco_read_reg(TCO1_CNT);
86 tcocnt |= TCO_TMR_HLT;
87 tco_write_reg(TCO1_CNT, tcocnt);
88}
89
Michael Niewöhner2bd2be52020-03-03 20:47:01 +010090/* Enable and initialize TCO intruder SMI */
91static void tco_intruder_smi_enable(void)
92{
93 uint16_t tcocnt;
94
95 /* Make TCO issue an SMI on INTRD_DET assertion */
96 tcocnt = tco_read_reg(TCO2_CNT);
97 tcocnt &= ~TCO_INTRD_SEL_MASK;
98 tcocnt |= TCO_INTRD_SEL_SMI;
99 tco_write_reg(TCO2_CNT, tcocnt);
100}
101
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530102/* Enable TCO BAR using SMBUS TCO base to access TCO related register */
103static void tco_enable_bar(void)
104{
105 uint32_t reg32;
106 uint16_t tcobase;
Angel Pons24f46232021-04-17 12:08:15 +0200107 const pci_devfn_t dev = PCH_DEV_SMBUS;
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530108
109 /* Disable TCO in SMBUS Device first before changing Base Address */
110 reg32 = pci_read_config32(dev, TCOCTL);
111 reg32 &= ~TCO_BASE_EN;
112 pci_write_config32(dev, TCOCTL, reg32);
113
114 /* Program TCO Base */
115 tcobase = tco_get_bar();
116 pci_write_config32(dev, TCOBASE, tcobase);
117
118 /* Enable TCO in SMBUS */
119 pci_write_config32(dev, TCOCTL, reg32 | TCO_BASE_EN);
120
Subrata Banik211be9c2022-04-13 12:13:09 +0530121 /* Program TCO Base Address */
122 gpmr_write32(GPMR_TCOBASE, tcobase | GPMR_TCOEN);
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530123}
124
125/*
126 * Enable TCO BAR using SMBUS TCO base to access TCO related register
127 * also disable the timer.
128 */
129void tco_configure(void)
130{
Julius Wernercd49cce2019-03-05 16:53:33 -0800131 if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCO_ENABLE_THROUGH_SMBUS))
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530132 tco_enable_bar();
133
134 tco_timer_disable();
Michael Niewöhner2bd2be52020-03-03 20:47:01 +0100135
136 /* Enable intruder interrupt if TCO interrupts are enabled*/
137 if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE))
138 tco_intruder_smi_enable();
Subrata Banik7bc4dc52018-05-17 18:40:32 +0530139}