1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #define __SIMPLE_DEVICE__
6 #include <device/pci_ops.h>
7 #include <device/device.h>
8 #include <device/pci.h>
9 #include <intelblocks/gpmr.h>
10 #include <intelblocks/pcr.h>
11 #include <intelblocks/pmclib.h>
12 #include <intelblocks/tco.h>
13 #include <soc/iomap.h>
14 #include <soc/pci_devs.h>
15 #include <soc/pcr_ids.h>
17 #include <soc/smbus.h>
19 /* SMBUS TCO base address. */
22 #define TCO_BASE_EN (1 << 8)
23 #define TCO_BASE_LOCK (1 << 0)
25 #define TCO_TMR_MIN_VALUE 2
26 #define TCO_TMR_MAX_VALUE 1023
27 #define TCO_TMR_PERIOD_MS 600
29 uint16_t tco_get_bar(void)
31 return TCO_BASE_ADDRESS
;
34 uint16_t tco_read_reg(uint16_t tco_reg
)
38 tcobase
= tco_get_bar();
40 return inw(tcobase
+ tco_reg
);
43 void tco_write_reg(uint16_t tco_reg
, uint16_t value
)
47 tcobase
= tco_get_bar();
49 outw(value
, tcobase
+ tco_reg
);
52 void tco_lockdown(void)
55 const pci_devfn_t dev
= PCH_DEV_SMBUS
;
57 /* TCO base address lockdown */
58 pci_or_config32(dev
, TCOCTL
, TCO_BASE_LOCK
);
61 tcocnt
= tco_read_reg(TCO1_CNT
);
63 tco_write_reg(TCO1_CNT
, tcocnt
);
66 uint32_t tco_reset_status(void)
71 /* TCO Status 1 register */
72 tco1_sts
= tco_read_reg(TCO1_STS
);
73 tco_write_reg(TCO1_STS
, tco1_sts
);
75 /* TCO Status 2 register */
76 tco2_sts
= tco_read_reg(TCO2_STS
);
77 tco_write_reg(TCO2_STS
, tco2_sts
| TCO2_STS_SECOND_TO
);
79 if (CONFIG(ACPI_WDAT_WDT
))
80 tco_write_reg(TCO_MESSAGE1
, tco2_sts
& TCO2_STS_SECOND_TO
);
82 return (tco2_sts
<< 16) | tco1_sts
;
86 static void tco_timer_disable(void)
90 /* Program TCO timer halt */
91 tcocnt
= tco_read_reg(TCO1_CNT
);
92 tcocnt
|= TCO1_TMR_HLT
;
93 tco_write_reg(TCO1_CNT
, tcocnt
);
96 /* Enable and initialize TCO intruder SMI */
97 static void tco_intruder_smi_enable(void)
101 /* Make TCO issue an SMI on INTRD_DET assertion */
102 tcocnt
= tco_read_reg(TCO2_CNT
);
103 tcocnt
&= ~TCO2_INTRD_SEL_MASK
;
104 tcocnt
|= TCO2_INTRD_SEL_SMI
;
105 tco_write_reg(TCO2_CNT
, tcocnt
);
108 /* Enable TCO BAR using SMBUS TCO base to access TCO related register */
109 static void tco_enable_bar(void)
113 const pci_devfn_t dev
= PCH_DEV_SMBUS
;
115 /* Disable TCO in SMBUS Device first before changing Base Address */
116 reg32
= pci_read_config32(dev
, TCOCTL
);
117 reg32
&= ~TCO_BASE_EN
;
118 pci_write_config32(dev
, TCOCTL
, reg32
);
120 /* Program TCO Base */
121 tcobase
= tco_get_bar();
122 pci_write_config32(dev
, TCOBASE
, tcobase
);
124 /* Enable TCO in SMBUS */
125 pci_write_config32(dev
, TCOCTL
, reg32
| TCO_BASE_EN
);
127 /* Program TCO Base Address */
128 gpmr_write32(GPMR_TCOBASE
, tcobase
| GPMR_TCOEN
);
132 * Enable TCO BAR using SMBUS TCO base to access TCO related register
133 * also disable the timer.
135 void tco_configure(void)
137 if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCO_ENABLE_THROUGH_SMBUS
))
142 /* Enable intruder interrupt if TCO interrupts are enabled*/
143 if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE
))
144 tco_intruder_smi_enable();
147 uint32_t tco_get_timer_period(void)
149 return TCO_TMR_PERIOD_MS
;
152 uint32_t tco_get_timer_min_value(void)
154 return TCO_TMR_MIN_VALUE
;
157 uint32_t tco_get_timer_max_value(void)
159 return TCO_TMR_MAX_VALUE
;