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