xref: /openbmc/hiomapd/lpc.c (revision 0297e5b8)
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