1cd18611eSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
2cd18611eSAndrew Jeffery // Copyright (C) 2018 IBM Corp.
3cd18611eSAndrew Jeffery
4cd18611eSAndrew Jeffery #define _GNU_SOURCE
5cd18611eSAndrew Jeffery #include <assert.h>
6cd18611eSAndrew Jeffery #include <errno.h>
7cd18611eSAndrew Jeffery #include <fcntl.h>
8cd18611eSAndrew Jeffery #include <getopt.h>
9cd18611eSAndrew Jeffery #include <limits.h>
10cd18611eSAndrew Jeffery #include <poll.h>
11cd18611eSAndrew Jeffery #include <stdbool.h>
12cd18611eSAndrew Jeffery #include <stdint.h>
13cd18611eSAndrew Jeffery #include <stdio.h>
14cd18611eSAndrew Jeffery #include <stdlib.h>
15cd18611eSAndrew Jeffery #include <string.h>
16cd18611eSAndrew Jeffery #include <syslog.h>
17cd18611eSAndrew Jeffery #include <signal.h>
18cd18611eSAndrew Jeffery #include <sys/ioctl.h>
19cd18611eSAndrew Jeffery #include <sys/mman.h>
20cd18611eSAndrew Jeffery #include <sys/stat.h>
21cd18611eSAndrew Jeffery #include <sys/timerfd.h>
22cd18611eSAndrew Jeffery #include <sys/types.h>
23cd18611eSAndrew Jeffery #include <time.h>
24cd18611eSAndrew Jeffery #include <unistd.h>
25cd18611eSAndrew Jeffery #include <inttypes.h>
26cd18611eSAndrew Jeffery
2726558dbbSAndrew Jeffery #include "mboxd.h"
28cd18611eSAndrew Jeffery #include "common.h"
29cd18611eSAndrew Jeffery #include "lpc.h"
30f1e547c7SEvan Lojewski #include "backend.h"
31cd18611eSAndrew Jeffery #include <linux/aspeed-lpc-ctrl.h>
32cd18611eSAndrew Jeffery
33cd18611eSAndrew Jeffery #define LPC_CTRL_PATH "/dev/aspeed-lpc-ctrl"
34cd18611eSAndrew Jeffery
__lpc_dev_init(struct mbox_context * context,const char * path)35cb9b2100SAndrew Jeffery int __lpc_dev_init(struct mbox_context *context, const char *path)
36cd18611eSAndrew Jeffery {
37cd18611eSAndrew Jeffery struct aspeed_lpc_ctrl_mapping map = {
38cd18611eSAndrew Jeffery .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
39cd18611eSAndrew Jeffery .window_id = 0, /* There's only one */
40cd18611eSAndrew Jeffery .flags = 0,
41cd18611eSAndrew Jeffery .addr = 0,
42cd18611eSAndrew Jeffery .offset = 0,
43cd18611eSAndrew Jeffery .size = 0
44cd18611eSAndrew Jeffery };
45cd18611eSAndrew Jeffery int fd;
46cd18611eSAndrew Jeffery
47cd18611eSAndrew Jeffery /* Open LPC Device */
48cd18611eSAndrew Jeffery MSG_DBG("Opening %s\n", path);
49cd18611eSAndrew Jeffery fd = open(path, O_RDWR | O_SYNC);
50cd18611eSAndrew Jeffery if (fd < 0) {
51cd18611eSAndrew Jeffery MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
52cd18611eSAndrew Jeffery path, strerror(errno));
53cd18611eSAndrew Jeffery return -errno;
54cd18611eSAndrew Jeffery }
55cd18611eSAndrew Jeffery
56cd18611eSAndrew Jeffery context->fds[LPC_CTRL_FD].fd = fd;
57cd18611eSAndrew Jeffery
58cd18611eSAndrew Jeffery /* Find Size of Reserved Memory Region */
59cd18611eSAndrew Jeffery MSG_DBG("Getting buffer size...\n");
60cd18611eSAndrew Jeffery if (ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map) < 0) {
61cd18611eSAndrew Jeffery MSG_ERR("Couldn't get lpc control buffer size: %s\n",
62cd18611eSAndrew Jeffery strerror(errno));
63cd18611eSAndrew Jeffery return -errno;
64cd18611eSAndrew Jeffery }
65cd18611eSAndrew Jeffery
66cd18611eSAndrew Jeffery context->mem_size = map.size;
67cd18611eSAndrew Jeffery /* Map at the top of the 28-bit LPC firmware address space-0 */
68cd18611eSAndrew Jeffery context->lpc_base = 0x0FFFFFFF & -context->mem_size;
69cd18611eSAndrew Jeffery
70cd18611eSAndrew Jeffery /* mmap the Reserved Memory Region */
71cd18611eSAndrew Jeffery MSG_DBG("Mapping in 0x%.8x bytes of %s\n", context->mem_size, path);
72cd18611eSAndrew Jeffery context->mem = mmap(NULL, context->mem_size, PROT_READ | PROT_WRITE,
73cd18611eSAndrew Jeffery MAP_SHARED, fd, 0);
74cd18611eSAndrew Jeffery if (context->mem == MAP_FAILED) {
75cd18611eSAndrew Jeffery MSG_ERR("Failed to map %s: %s\n", path, strerror(errno));
76cd18611eSAndrew Jeffery return -errno;
77cd18611eSAndrew Jeffery }
78cd18611eSAndrew Jeffery
79cd18611eSAndrew Jeffery return 0;
80cd18611eSAndrew Jeffery }
81cd18611eSAndrew Jeffery
lpc_dev_init(struct mbox_context * context)82cb9b2100SAndrew Jeffery int lpc_dev_init(struct mbox_context *context)
83cd18611eSAndrew Jeffery {
84cb9b2100SAndrew Jeffery return __lpc_dev_init(context, LPC_CTRL_PATH);
85cd18611eSAndrew Jeffery }
86cd18611eSAndrew Jeffery
lpc_dev_free(struct mbox_context * context)872e2df286SAndrew Jeffery void lpc_dev_free(struct mbox_context *context)
88cd18611eSAndrew Jeffery {
89cd18611eSAndrew Jeffery if (context->mem) {
90cd18611eSAndrew Jeffery munmap(context->mem, context->mem_size);
91cd18611eSAndrew Jeffery }
92cd18611eSAndrew Jeffery close(context->fds[LPC_CTRL_FD].fd);
93cd18611eSAndrew Jeffery }
94cd18611eSAndrew Jeffery
95cd18611eSAndrew Jeffery /*
96ec0f2305SAndrew Jeffery * lpc_map_flash() - Point the lpc bus mapping to the actual flash device
97cd18611eSAndrew Jeffery * @context: The mbox context pointer
98cd18611eSAndrew Jeffery *
99cd18611eSAndrew Jeffery * Return: 0 on success otherwise negative error code
100cd18611eSAndrew Jeffery */
lpc_map_flash(struct mbox_context * context)101ec0f2305SAndrew Jeffery int lpc_map_flash(struct mbox_context *context)
102cd18611eSAndrew Jeffery {
103cd18611eSAndrew Jeffery struct aspeed_lpc_ctrl_mapping map = {
104cd18611eSAndrew Jeffery .window_type = ASPEED_LPC_CTRL_WINDOW_FLASH,
105cd18611eSAndrew Jeffery .window_id = 0, /* Theres only one */
106cd18611eSAndrew Jeffery .flags = 0,
107cd18611eSAndrew Jeffery /*
108cd18611eSAndrew Jeffery * The mask is because the top nibble is the host LPC FW space,
109cd18611eSAndrew Jeffery * we want space 0.
110cd18611eSAndrew Jeffery */
111f1e547c7SEvan Lojewski .addr = 0x0FFFFFFF & -context->backend.flash_size,
112cd18611eSAndrew Jeffery .offset = 0,
113f1e547c7SEvan Lojewski .size = context->backend.flash_size
114cd18611eSAndrew Jeffery };
115cd18611eSAndrew Jeffery
116cd18611eSAndrew Jeffery if (context->state & MAPS_FLASH) {
117cd18611eSAndrew Jeffery return 0; /* LPC Bus already points to flash */
118cd18611eSAndrew Jeffery }
119cd18611eSAndrew Jeffery /* Don't let the host access flash while we're suspended */
120cd18611eSAndrew Jeffery if (context->state & STATE_SUSPENDED) {
121cd18611eSAndrew Jeffery MSG_ERR("Can't point lpc mapping to flash while suspended\n");
1228eab2151SAndrew Jeffery return -EBUSY;
123cd18611eSAndrew Jeffery }
124cd18611eSAndrew Jeffery
125cd18611eSAndrew Jeffery MSG_INFO("Pointing HOST LPC bus at the flash\n");
126cd18611eSAndrew Jeffery MSG_INFO("Assuming %dMB of flash: HOST LPC 0x%08x\n",
127f1e547c7SEvan Lojewski context->backend.flash_size >> 20, map.addr);
128cd18611eSAndrew Jeffery
129cd18611eSAndrew Jeffery if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map)
130cd18611eSAndrew Jeffery == -1) {
131cd18611eSAndrew Jeffery MSG_ERR("Failed to point the LPC BUS at the actual flash: %s\n",
132cd18611eSAndrew Jeffery strerror(errno));
1338eab2151SAndrew Jeffery return -errno;
134cd18611eSAndrew Jeffery }
135cd18611eSAndrew Jeffery
136cd18611eSAndrew Jeffery context->state = ACTIVE_MAPS_FLASH;
137cd18611eSAndrew Jeffery /*
138cd18611eSAndrew Jeffery * Since the host now has access to the flash it can change it out from
139cd18611eSAndrew Jeffery * under us
140cd18611eSAndrew Jeffery */
141*0297e5b8SAndrew Jeffery return backend_set_bytemap(&context->backend, 0,
142*0297e5b8SAndrew Jeffery context->backend.flash_size, FLASH_DIRTY);
143cd18611eSAndrew Jeffery }
144cd18611eSAndrew Jeffery
145cd18611eSAndrew Jeffery /*
14617079d1dSAndrew Jeffery * lpc_map_memory() - Point the lpc bus mapping to the reserved memory region
147cd18611eSAndrew Jeffery * @context: The mbox context pointer
148cd18611eSAndrew Jeffery *
149cd18611eSAndrew Jeffery * Return: 0 on success otherwise negative error code
150cd18611eSAndrew Jeffery */
lpc_map_memory(struct mbox_context * context)15117079d1dSAndrew Jeffery int lpc_map_memory(struct mbox_context *context)
152cd18611eSAndrew Jeffery {
153cd18611eSAndrew Jeffery struct aspeed_lpc_ctrl_mapping map = {
154cd18611eSAndrew Jeffery .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
155cd18611eSAndrew Jeffery .window_id = 0, /* There's only one */
156cd18611eSAndrew Jeffery .flags = 0,
157cd18611eSAndrew Jeffery .addr = context->lpc_base,
158cd18611eSAndrew Jeffery .offset = 0,
159cd18611eSAndrew Jeffery .size = context->mem_size
160cd18611eSAndrew Jeffery };
161cd18611eSAndrew Jeffery
162cd18611eSAndrew Jeffery if (context->state & MAPS_MEM) {
163cd18611eSAndrew Jeffery return 0; /* LPC Bus already points to reserved memory area */
164cd18611eSAndrew Jeffery }
165cd18611eSAndrew Jeffery
166cd18611eSAndrew Jeffery MSG_INFO("Pointing HOST LPC bus at memory region %p of size 0x%.8x\n",
167cd18611eSAndrew Jeffery context->mem, context->mem_size);
168cd18611eSAndrew Jeffery MSG_INFO("LPC address 0x%.8x\n", map.addr);
169cd18611eSAndrew Jeffery
170cd18611eSAndrew Jeffery if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP,
171cd18611eSAndrew Jeffery &map)) {
172cd18611eSAndrew Jeffery MSG_ERR("Failed to point the LPC BUS to memory: %s\n",
173cd18611eSAndrew Jeffery strerror(errno));
1741e531afdSAndrew Jeffery return -errno;
175cd18611eSAndrew Jeffery }
176cd18611eSAndrew Jeffery
177cd18611eSAndrew Jeffery /* LPC now maps memory (keep suspended state) */
178cd18611eSAndrew Jeffery context->state = MAPS_MEM | (context->state & STATE_SUSPENDED);
179cd18611eSAndrew Jeffery
180cd18611eSAndrew Jeffery return 0;
181cd18611eSAndrew Jeffery }
182