150 lines
3.6 KiB
C
150 lines
3.6 KiB
C
/* Copyright 2013-2014 IBM Corp.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
* implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
|
|
/* Where to put the firmware image if booting from memory */
|
|
#define MEM_IMG_BASE (0x5c000000)
|
|
|
|
/* Start of flash memory if booting from flash */
|
|
#define FLASH_IMG_BASE (0x30000000)
|
|
|
|
/* LPC registers */
|
|
#define LPC_BASE 0x1e789000
|
|
#define LPC_HICR6 0x80
|
|
#define LPC_HICR7 0x88
|
|
#define LPC_HICR8 0x8c
|
|
#define LPC_SCR0SIO 0x170
|
|
|
|
#define MEMBOOT_SIO_VERSION_FLAG 0x42
|
|
#define MEMBOOT_SIO_FLAG (0x10 << 8)
|
|
|
|
uint32_t readl(void *addr)
|
|
{
|
|
asm volatile("" : : : "memory");
|
|
return *(volatile uint32_t *)addr;
|
|
}
|
|
|
|
void writel(uint32_t val, void *addr)
|
|
{
|
|
asm volatile("" : : : "memory");
|
|
*(volatile uint32_t *)addr = val;
|
|
}
|
|
|
|
void copy_flash_img(int mem_fd, int flash_fd, unsigned int size)
|
|
{
|
|
static void *memimg, *fwimg;
|
|
size_t pagesize = getpagesize();
|
|
|
|
memimg = mmap(NULL, ((size/pagesize)+1)*pagesize,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, MEM_IMG_BASE);
|
|
if (memimg == MAP_FAILED) {
|
|
perror("Unable to map image destination memory");
|
|
exit(1);
|
|
}
|
|
|
|
fwimg = mmap(NULL,size, PROT_READ, MAP_SHARED, flash_fd, 0);
|
|
if (fwimg == MAP_FAILED) {
|
|
perror("Unable to open image source memory");
|
|
exit(1);
|
|
}
|
|
|
|
/* Copy boot image */
|
|
memcpy(memimg, fwimg, size);
|
|
}
|
|
|
|
void boot_firmware_image(int mem_fd, char *filename)
|
|
{
|
|
int fw_fd;
|
|
struct stat st;
|
|
|
|
fw_fd = open(filename, O_RDONLY);
|
|
if (fw_fd < 0) {
|
|
perror("Unable to open flash image\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (stat(filename, &st)) {
|
|
perror("Unable to determine size of firmware image");
|
|
exit(1);
|
|
}
|
|
|
|
if (st.st_size > 32*1024*1024) {
|
|
fprintf(stderr, "Flash too large (> 32MB)");
|
|
exit(1);
|
|
}
|
|
|
|
copy_flash_img(mem_fd, fw_fd, st.st_size);
|
|
close(fw_fd);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int mem_fd;
|
|
void *lpcreg;
|
|
uint32_t lpc_scr0sio_val;
|
|
uint32_t lpc_hicr7_val = (FLASH_IMG_BASE | 0xe00);
|
|
|
|
if (argc > 2) {
|
|
printf("Usage: %s <flash image>\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
|
if (mem_fd < 0) {
|
|
perror("Unable to open /dev/mem");
|
|
exit(1);
|
|
}
|
|
|
|
lpcreg = mmap(NULL, getpagesize(),
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, LPC_BASE);
|
|
if (lpcreg == MAP_FAILED) {
|
|
perror("Unable to map LPC register memory");
|
|
exit(1);
|
|
}
|
|
|
|
lpc_scr0sio_val = readl(lpcreg+LPC_SCR0SIO);
|
|
lpc_scr0sio_val &= ~0xff;
|
|
lpc_scr0sio_val |= MEMBOOT_SIO_VERSION_FLAG;
|
|
lpc_scr0sio_val &= ~MEMBOOT_SIO_FLAG;
|
|
|
|
if (argc == 2) {
|
|
boot_firmware_image(mem_fd, argv[1]);
|
|
lpc_hicr7_val = (MEM_IMG_BASE | 0xe00);
|
|
|
|
/* Set the boot mode scratch register to indicate a memboot */
|
|
lpc_scr0sio_val |= MEMBOOT_SIO_FLAG;
|
|
printf("Booting from memory after power cycle\n");
|
|
}
|
|
|
|
if (readl(lpcreg + LPC_HICR7) != lpc_hicr7_val) {
|
|
printf("Resetting LPC_HICR7 to 0x%x\n", lpc_hicr7_val);
|
|
writel(lpc_hicr7_val, lpcreg+LPC_HICR7);
|
|
}
|
|
|
|
/* Set the magic value */
|
|
writel(0x42, lpcreg+LPC_SCR0SIO);
|
|
|
|
writel(lpc_scr0sio_val, lpcreg+LPC_SCR0SIO);
|
|
printf("LPC_HICR7 = 0x%x\n", lpc_hicr7_val);
|
|
return 0;
|
|
}
|