blob: 7decf790a9e7d021bcc2c4aa4b4df98dca4d9008 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/mmio.h>
#include <console/console.h>
#include <delay.h>
#include <intelblocks/pmclib.h>
#include <intelblocks/pmc_ipc.h>
#include <stdint.h>
#include <timer.h>
/*
* WBUF register block offset 0x80..0x8f there are 4 consecutive
* 32 bit registers
*/
#define IPC_WBUF0 0x80
/*
* RBUF registers block offset 0x90..0x9f there are 4 consecutive
* 32 bit registers
*/
#define IPC_RBUF0 0x90
/*
* From Intel 500 Series PCH EDS vol2 s4.4
*/
#define PMC_IPC_CMD_OFFSET 0x0
#define PMC_IPC_STS_OFFSET 0x4
#define PMC_IPC_STS_BUSY BIT(0)
#define PMC_IPC_STS_ERR BIT(1)
#define PMC_IPC_ERR_CODE_SHIFT 16
#define PMC_IPC_ERR_CODE_MASK 0xff
#define PMC_IPC_XFER_TIMEOUT_MS (1 * MSECS_PER_SEC) /* max 1s */
#define IS_IPC_STS_BUSY(status) ((status) & PMC_IPC_STS_BUSY)
#define IPC_STS_HAS_ERROR(status) ((status) & PMC_IPC_STS_ERR)
#define IPC_STS_ERROR_CODE(sts) (((sts) >> PMC_IPC_ERR_CODE_SHIFT & \
PMC_IPC_ERR_CODE_MASK))
static void *pmc_reg(unsigned int pmc_reg_offset)
{
const uintptr_t pmcbase = soc_read_pmc_base();
return (void *)(pmcbase + pmc_reg_offset);
}
static const void *pmc_rbuf(unsigned int ix)
{
return pmc_reg(IPC_RBUF0 + ix * sizeof(uint32_t));
}
static void *pmc_wbuf(unsigned int ix)
{
return pmc_reg(IPC_WBUF0 + ix * sizeof(uint32_t));
}
static int check_ipc_sts(void)
{
struct stopwatch sw;
uint32_t ipc_sts;
stopwatch_init_msecs_expire(&sw, PMC_IPC_XFER_TIMEOUT_MS);
do {
ipc_sts = read32(pmc_reg(PMC_IPC_STS_OFFSET));
if (!(IS_IPC_STS_BUSY(ipc_sts))) {
if (IPC_STS_HAS_ERROR(ipc_sts)) {
printk(BIOS_ERR, "IPC_STS.error_code 0x%x\n",
IPC_STS_ERROR_CODE(ipc_sts));
return -1;
}
return 0;
}
udelay(50);
} while (!stopwatch_expired(&sw));
printk(BIOS_ERR, "PMC IPC timeout after %u ms\n", PMC_IPC_XFER_TIMEOUT_MS);
return -1;
}
enum cb_err pmc_send_ipc_cmd(uint32_t cmd, const struct pmc_ipc_buffer *wbuf,
struct pmc_ipc_buffer *rbuf)
{
for (int i = 0; i < PMC_IPC_BUF_COUNT; ++i)
write32(pmc_wbuf(i), wbuf->buf[i]);
write32(pmc_reg(PMC_IPC_CMD_OFFSET), cmd);
if (check_ipc_sts()) {
printk(BIOS_ERR, "PMC IPC command 0x%x failed\n", cmd);
return CB_ERR;
}
for (int i = 0; i < PMC_IPC_BUF_COUNT; ++i)
rbuf->buf[i] = read32(pmc_rbuf(i));
return CB_SUCCESS;
}
|