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 "mbox.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 -MBOX_R_PARAM_ERROR; 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 -MBOX_R_SYSTEM_ERROR; 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 -MBOX_R_SYSTEM_ERROR; 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