1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) ASPEED Technology Inc.
4  */
5 #include <common.h>
6 #include <asm/io.h>
7 
8 #define SCU_BASE	0x1e6e2000
9 #define ESPI_BASE	0x1e6ee000
10 #define LPC_BASE	0x1e789000
11 #define   LPC_HICR5		(LPC_BASE + 0x80)
12 #define   LPC_HICR6		(LPC_BASE + 0x84)
13 #define   LPC_SNPWADR	(LPC_BASE + 0x90)
14 #define   LPC_HICRB		(LPC_BASE + 0x100)
15 #define GPIO_BASE	0x1e780000
16 
17 /* HICR5 Bits */
18 #define HICR5_EN_SIOGIO (1 << 31)		/* Enable SIOGIO */
19 #define HICR5_EN80HGIO (1 << 30)		/* Enable 80hGIO */
20 #define HICR5_SEL80HGIO (0x1f << 24)		/* Select 80hGIO */
21 #define SET_SEL80HGIO(x) ((x & 0x1f) << 24)	/* Select 80hGIO Offset */
22 #define HICR5_UNKVAL_MASK 0x1FFF0000		/* Bits with unknown values on reset */
23 #define HICR5_ENINT_SNP0W (1 << 1)		/* Enable Snooping address 0 */
24 #define HICR5_EN_SNP0W (1 << 0)			/* Enable Snooping address 0 */
25 
26 /* HRCR6 Bits */
27 #define HICR6_STR_SNP0W (1 << 0)	/* Interrupt Status Snoop address 0 */
28 #define HICR6_STR_SNP1W (1 << 1)	/* Interrupt Status Snoop address 1 */
29 
30 /* HICRB Bits */
31 #define HICRB_EN80HSGIO (1 << 13)	/* Enable 80hSGIO */
32 
33 static void __maybe_unused port80h_snoop_init(void)
34 {
35 	u32 value;
36 	/* enable port80h snoop and sgpio */
37 	/* set lpc snoop #0 to port 0x80 */
38 	value = readl(LPC_SNPWADR) & 0xffff0000;
39 	writel(value | 0x80, LPC_SNPWADR);
40 
41 	/* clear interrupt status */
42 	value = readl(LPC_HICR6);
43 	value |= HICR6_STR_SNP0W | HICR6_STR_SNP1W;
44 	writel(value, LPC_HICR6);
45 
46 	/* enable lpc snoop #0 and SIOGIO */
47 	value = readl(LPC_HICR5) & ~(HICR5_UNKVAL_MASK);
48 	value |= HICR5_EN_SIOGIO | HICR5_EN_SNP0W;
49 	writel(value, LPC_HICR5);
50 
51 	/* enable port80h snoop on SGPIO */
52 	value = readl(LPC_HICRB) | HICRB_EN80HSGIO;
53 	writel(value, LPC_HICRB);
54 }
55 
56 static void __maybe_unused sgpio_init(void)
57 {
58 #define SGPIO_CLK_DIV(N)	((N) << 16)
59 #define SGPIO_BYTES(N)		((N) << 6)
60 #define SGPIO_ENABLE		1
61 #define GPIO554			0x554
62 #define SCU_414			0x414 /* Multi-function Pin Control #5 */
63 #define SCU_414_SGPM_MASK	GENMASK(27, 24)
64 
65 	u32 value;
66 	/* set the sgpio clock to pclk/(2*(5+1)) or ~2 MHz */
67 	value = SGPIO_CLK_DIV(256) | SGPIO_BYTES(10) | SGPIO_ENABLE;
68 	writel(value, GPIO_BASE + GPIO554);
69 	writel(readl(SCU_BASE | SCU_414) | SCU_414_SGPM_MASK,
70 		SCU_BASE | SCU_414);
71 }
72 
73 static void __maybe_unused espi_init(void)
74 {
75 	u32 reg;
76 
77 	/*
78 	 * Aspeed STRONGLY NOT recommend to use eSPI early init.
79 	 *
80 	 * This eSPI early init sequence merely set OOB_FREE. It
81 	 * is NOT able to actually handle OOB requests from PCH.
82 	 *
83 	 * During the power on stage, PCH keep waiting OOB_FREE
84 	 * to continue its booting. In general, OOB_FREE is set
85 	 * when BMC firmware is ready. That is, the eSPI kernel
86 	 * driver is mounted and ready to serve eSPI. However,
87 	 * it means that PCH must wait until BMC kernel ready.
88 	 *
89 	 * For customers that request PCH booting as soon as
90 	 * possible. You may use this early init to set OOB_FREE
91 	 * to prevent PCH from blocking by OOB_FREE before BMC
92 	 * kernel ready.
93 	 *
94 	 * If you are not sure what you are doing, DO NOT use it.
95 	 */
96 	reg = readl(ESPI_BASE + 0x000);
97 	reg |= 0xef;
98 	writel(reg, ESPI_BASE + 0x000);
99 
100 	writel(0x0, ESPI_BASE + 0x110);
101 	writel(0x0, ESPI_BASE + 0x114);
102 
103 	reg = readl(ESPI_BASE + 0x00c);
104 	reg |= 0x80000000;
105 	writel(reg, ESPI_BASE + 0x00c);
106 
107 	writel(0xffffffff, ESPI_BASE + 0x094);
108 	writel(0x1, ESPI_BASE + 0x100);
109 	writel(0x1, ESPI_BASE + 0x120);
110 
111 	reg = readl(ESPI_BASE + 0x080);
112 	reg |= 0x50;
113 	writel(reg, ESPI_BASE + 0x080);
114 
115 	reg = readl(ESPI_BASE + 0x000);
116 	reg |= 0x10;
117 	writel(reg, ESPI_BASE + 0x000);
118 }
119 
120 int board_early_init_f(void)
121 {
122 #if 0
123 	port80h_snoop_init();
124 	sgpio_init();
125 #endif
126 	espi_init();
127 	return 0;
128 }
129