xref: /aosp_15_r20/external/coreboot/src/drivers/pc80/rtc/post.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <stdint.h>
4 #include <post.h>
5 #include <console/console.h>
6 #include <device/device.h>
7 #include <pc80/mc146818rtc.h>
8 #include <smp/spinlock.h>
9 
10 #if CONFIG(USE_OPTION_TABLE)
11 # include "option_table.h"
12 # define CMOS_POST_OFFSET (CMOS_VSTART_cmos_post_offset >> 3)
13 #else
14 # if (CONFIG_CMOS_POST_OFFSET != 0)
15 #  define CMOS_POST_OFFSET CONFIG_CMOS_POST_OFFSET
16 # else
17 #  error "Must configure CONFIG_CMOS_POST_OFFSET"
18 # endif
19 #endif
20 
21 /*
22  *    0 = Bank Select Magic
23  *    1 = Bank 0 POST
24  *    2 = Bank 1 POST
25  *  3-6 = BANK 0 Extra log
26  * 7-10 = BANK 1 Extra log
27  */
28 #define CMOS_POST_BANK_OFFSET     (CMOS_POST_OFFSET)
29 #define CMOS_POST_BANK_0_MAGIC    0x80
30 #define CMOS_POST_BANK_0_OFFSET   (CMOS_POST_OFFSET + 1)
31 #define CMOS_POST_BANK_0_EXTRA    (CMOS_POST_OFFSET + 3)
32 #define CMOS_POST_BANK_1_MAGIC    0x81
33 #define CMOS_POST_BANK_1_OFFSET   (CMOS_POST_OFFSET + 2)
34 #define CMOS_POST_BANK_1_EXTRA    (CMOS_POST_OFFSET + 7)
35 
36 #define CMOS_POST_EXTRA_DEV_PATH  0x01
37 
DECLARE_SPIN_LOCK(cmos_post_lock)38 DECLARE_SPIN_LOCK(cmos_post_lock)
39 
40 int cmos_post_previous_boot(u8 *code, u32 *extra)
41 {
42 	*code = 0;
43 	*extra = 0;
44 
45 	spin_lock(&cmos_post_lock);
46 
47 	/* Get post code from other bank */
48 	switch (cmos_read(CMOS_POST_BANK_OFFSET)) {
49 	case CMOS_POST_BANK_0_MAGIC:
50 		*code = cmos_read(CMOS_POST_BANK_1_OFFSET);
51 		*extra = cmos_read32(CMOS_POST_BANK_1_EXTRA);
52 		break;
53 	case CMOS_POST_BANK_1_MAGIC:
54 		*code = cmos_read(CMOS_POST_BANK_0_OFFSET);
55 		*extra = cmos_read32(CMOS_POST_BANK_0_EXTRA);
56 		break;
57 	}
58 
59 	spin_unlock(&cmos_post_lock);
60 
61 	/* Check last post code in previous boot against normal list */
62 	switch (*code) {
63 	case POSTCODE_OS_BOOT:
64 	case POSTCODE_OS_RESUME:
65 	case POSTCODE_ENTER_ELF_BOOT:
66 	case 0:
67 		break;
68 	default:
69 		return -1;
70 	}
71 
72 	return 0;
73 }
74 
cmos_post_init(void)75 void cmos_post_init(void)
76 {
77 	u8 magic = CMOS_POST_BANK_0_MAGIC;
78 
79 	/* Switch to the other bank */
80 	switch (cmos_read(CMOS_POST_BANK_OFFSET)) {
81 	case CMOS_POST_BANK_1_MAGIC:
82 		break;
83 	case CMOS_POST_BANK_0_MAGIC:
84 		magic = CMOS_POST_BANK_1_MAGIC;
85 		break;
86 	default:
87 		/* Initialize to zero */
88 		cmos_write(0, CMOS_POST_BANK_0_OFFSET);
89 		cmos_write(0, CMOS_POST_BANK_1_OFFSET);
90 		cmos_write32(0, CMOS_POST_BANK_0_EXTRA);
91 		cmos_write32(0, CMOS_POST_BANK_1_EXTRA);
92 	}
93 
94 	cmos_write(magic, CMOS_POST_BANK_OFFSET);
95 }
96 
cmos_post_code(u8 value)97 void cmos_post_code(u8 value)
98 {
99 	spin_lock(&cmos_post_lock);
100 
101 	switch (cmos_read(CMOS_POST_BANK_OFFSET)) {
102 	case CMOS_POST_BANK_0_MAGIC:
103 		cmos_write(value, CMOS_POST_BANK_0_OFFSET);
104 		break;
105 	case CMOS_POST_BANK_1_MAGIC:
106 		cmos_write(value, CMOS_POST_BANK_1_OFFSET);
107 		break;
108 	}
109 
110 	spin_unlock(&cmos_post_lock);
111 }
112 
cmos_post_extra(u32 value)113 void cmos_post_extra(u32 value)
114 {
115 	spin_lock(&cmos_post_lock);
116 
117 	switch (cmos_read(CMOS_POST_BANK_OFFSET)) {
118 	case CMOS_POST_BANK_0_MAGIC:
119 		cmos_write32(value, CMOS_POST_BANK_0_EXTRA);
120 		break;
121 	case CMOS_POST_BANK_1_MAGIC:
122 		cmos_write32(value, CMOS_POST_BANK_1_EXTRA);
123 		break;
124 	}
125 
126 	spin_unlock(&cmos_post_lock);
127 }
128 
cmos_post_path(const struct device * dev)129 void cmos_post_path(const struct device *dev)
130 {
131 	/* Encode path into lower 3 bytes */
132 	u32 path = dev_path_encode(dev);
133 	/* Upper byte contains the log type */
134 	path |= CMOS_POST_EXTRA_DEV_PATH << 24;
135 	cmos_post_extra(path);
136 }
137