mbed support for LPC4088 Display Module
Dependencies: DM_FATFileSystem DM_HttpServer DM_USBHost EthernetInterface USBDevice mbed-rpc mbed-rtos mbed-src
Fork of DMSupport by
Diff: Bios/BiosLoader.cpp
- Revision:
- 22:1a58a518435c
- Child:
- 24:9a677afc86f1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bios/BiosLoader.cpp Fri Jan 16 11:13:39 2015 +0100 @@ -0,0 +1,263 @@ +/* + * Copyright 2014 Embedded Artists AB + * + * 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 "mbed.h" +#include "BiosLoader.h" +#include "DMBoard.h" +#include "BiosEEPROM.h" +#include "crc.h" +#include "bios.h" + +#if defined(DM_BOARD_BIOS_DEVELOPMENT) + #ifdef __cplusplus + extern "C" { + #endif + void bios_debug_aid(bios_header_t* header); + #ifdef __cplusplus + } + #endif +#endif + +/****************************************************************************** + * Defines and typedefs + *****************************************************************************/ + +#define MOVE_POINTER(__x, __off) ( ( (uint32_t*)(__x) ) = (uint32_t*)( (uint32_t)(__x) + (__off) ) ) + +/* + * Make sure that we reserve at least this amount of RAM for future + * expansion of the BIOS. This prevents the user from squeezing out + * the last drop of available RAM in his application. + */ +#define BIOS_RESERVED_CHUNK 0x1000 +#define BIOS_MAX_SIZE 0x100000 +#ifndef MAX + #define MAX(__a, __b) (((__a)>(__b))?(__a):(__b)) +#endif + + +/****************************************************************************** + * Local variables + *****************************************************************************/ + + +/****************************************************************************** + * Private Functions + *****************************************************************************/ + +// Function called from the BIOS +static uint32_t readTimeMs() +{ + return us_ticker_read()/1000; +} + + +BiosLoader::BiosLoader() : + _initialized(false), + _biosData(NULL), + _conf(NULL), + _confSize(0) +{ +} + +BiosLoader::~BiosLoader() +{ + if (_biosData != NULL) { + free(_biosData); + _biosData = NULL; + } + if (_conf != NULL) { + free(_conf); + _conf = NULL; + _confSize = 0; + } +} + +DMBoard::BoardError BiosLoader::readBIOS(uint8_t** data, uint32_t* size) +{ + DMBoard::BoardError err = DMBoard::Ok; + BiosEEPROM eeprom; + file_header_t fh; + + if (_conf != NULL) { + *data = _conf; + *size = _confSize; + return DMBoard::Ok; + } + + do { + if (!eeprom.read(0, (char*)&fh, sizeof(file_header_t))) { + resetI2C(); + if (!eeprom.read(0, (char*)&fh, sizeof(file_header_t))) { + err = DMBoard::BiosStorageError; + break; + } + } + + if (fh.magic != BIOS_MAGIC) { + err = DMBoard::BiosInvalidError; + break; + } + + if (fh.version != BIOS_VER) { + err = DMBoard::BiosVersionError; + break; + } + + if ((fh.headerSize + fh.size) > BIOS_MAX_SIZE) { + err = DMBoard::BiosInvalidError; + break; + } + + _confSize = fh.headerSize + fh.size; + _conf = (uint8_t*)malloc(MAX(_confSize,BIOS_RESERVED_CHUNK)); + if (_conf == NULL) { + _confSize = 0; + err = DMBoard::MemoryError; + break; + } + + if (!eeprom.read(0, (char*)_conf, _confSize)) { + err = DMBoard::BiosStorageError; + break; + } + + uint32_t crc = crc_Buffer((uint32_t*)(&_conf[fh.headerSize]), fh.size/4); + if (crc != fh.crc) { + err = DMBoard::BiosInvalidError; + break; + } + + // Bios header has been verified and seems ok + *data = _conf; + *size = _confSize; + err = DMBoard::Ok; + } while (false); + + if (err != DMBoard::Ok) { + if (_conf != NULL) { + free(_conf); + _conf = NULL; + _confSize = 0; + } + } + + return err; +} + +DMBoard::BoardError BiosLoader::params(bios_header_t** header, void** instanceData) +{ + if (!_initialized) { + DMBoard::BoardError err = init(); + if (err != DMBoard::Ok) { + return err; + } + } + if (_initialized) { + *header = &_bios; + *instanceData = _biosData; + return DMBoard::Ok; + } else { + return DMBoard::BiosInvalidError; + } +} + +DMBoard::BoardError BiosLoader::init() +{ + DMBoard::BoardError err = DMBoard::Ok; + if (!_initialized) { + do { + + // Get the display bios from the DMBoard. DMBoard will have verified it + // and will keep it in RAM so there is no need to copy it. + uint8_t* p = NULL; + uint32_t size = 0; + err = readBIOS(&p, &size); + if (err != BiosError_Ok) { + break; + } + + // Extract the function pointers so that they can be modified to match the + // actual location of the code + file_header_t* file_header = (file_header_t*)p; + memcpy(&_bios, &file_header->header, sizeof(bios_header_t)); + + // Allocate memory for the BIOS instance data + _biosData = malloc(file_header->paramSize); + if (_biosData == NULL) { + err = DMBoard::MemoryError; + break; + } + + // All offsets must be moved by two factors: + // 1) The position of the code in RAM (location of "p") + // 2) The header size (the code/data comes after it) + uint32_t offset = ((uint32_t)p) + file_header->headerSize; + uint32_t* functions = (uint32_t*)&_bios; + for (int i = 0; i < (sizeof(bios_header_t)/sizeof(uint32_t)); i++) { + functions[i] += offset; + } + +#if defined(DM_BOARD_BIOS_DEVELOPMENT) + // This requires that the project contains the source code for the BIOS + bios_debug_aid(&_bios); +#endif + + // Prepare the BIOS instance data before calling the first function + BiosError_t e = _bios.initParams(_biosData, SystemCoreClock, PeripheralClock, wait_us, readTimeMs); + if (e != BiosError_Ok) { + err = DMBoard::BiosInvalidError; + break; + } + + _initialized = true; + } while(0); + } + return err; +} + +void BiosLoader::resetI2C() +{ + DMBoard::instance().logger()->printf("BiosLoader::resetI2C()\n"); + DigitalOut reset(P0_23); + reset = 0; + wait_ms(1); + reset = 1; + wait_ms(10); +} + + +/****************************************************************************** + * Public Functions + *****************************************************************************/ + +bool BiosLoader::isKnownSPIFIMemory(uint8_t mfgr, uint8_t devType, uint8_t devID, uint32_t memSize, uint32_t* eraseBlockSize) +{ + if (!_initialized) { + DMBoard::BoardError err = init(); + if (err != DMBoard::Ok) { + return false; + } + } + if (_initialized) { + bool known = false; + BiosError_t err = _bios.spifiIsSupported(_biosData, mfgr,devType,devID,memSize,&known,eraseBlockSize); + if (err == BiosError_Ok) { + return known; + } + } + return false; +}