Skip to content

Commit

Permalink
add power management block device driver
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-723 committed Nov 14, 2023
1 parent 72f27ce commit d332210
Show file tree
Hide file tree
Showing 4 changed files with 514 additions and 0 deletions.
163 changes: 163 additions & 0 deletions storage/blockdevice/include/blockdevice/PowerManagementBlockDevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* mbed Microcontroller Library
* Copyright (c) 2022, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/

#ifndef MBED_POWER_MANAGEMENT_BLOCK_DEVICE_H
#define MBED_POWER_MANAGEMENT_BLOCK_DEVICE_H

#include "BlockDevice.h"
#include "platform/mbed_assert.h"

#if COMPONENT_QSPIF
enum {
QSPIF_HIGH_PERFORMANCE_MODE,
QSPIF_LOW_POWER_MODE,
QSPIF_DEEP_DOWN_MODE,
QSPIF_STANDBY_MODE,
};
#endif

namespace mbed {

class PowerManagementBlockDevice : public BlockDevice {
public:

/** Lifetime of the block device
*
* @param bd Block device to wrap as read only
*/
PowerManagementBlockDevice(BlockDevice *bd);

virtual ~PowerManagementBlockDevice();

/** Initialize a block device
*
* @return 0 on success or a negative error code on failure
*/
virtual int init();

/** Deinitialize a block device
*
* @return 0 on success or a negative error code on failure
*/
virtual int deinit();

/** Ensure data on storage is in sync with the driver
*
* @return 0 on success or a negative error code on failure
*/
virtual int sync();

/** Read blocks from a block device
*
* @param buffer Buffer to read blocks into
* @param addr Address of block to begin reading from
* @param size Size to read in bytes, must be a multiple of read block size
* @return 0 on success, negative error code on failure
*/
virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);

/** Program blocks to a block device
*
* The blocks must have been erased prior to being programmed
*
* @param buffer Buffer of data to write to blocks
* @param addr Address of block to begin writing to
* @param size Size to write in bytes, must be a multiple of program block size
* @return 0 on success, negative error code on failure
*/
virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);

/** Erase blocks on a block device
*
* The state of an erased block is undefined until it has been programmed,
* unless get_erase_value returns a non-negative byte value
*
* @param addr Address of block to begin erasing
* @param size Size to erase in bytes, must be a multiple of erase block size
* @return 0 on success, negative error code on failure
*/
virtual int erase(bd_addr_t addr, bd_size_t size);

/** Get the size of a readable block
*
* @return Size of a readable block in bytes
*/
virtual bd_size_t get_read_size() const;

/** Get the size of a programmable block
*
* @return Size of a programmable block in bytes
*/
virtual bd_size_t get_program_size() const;

/** Get the size of an erasable block
*
* @return Size of an erasable block in bytes
*/
virtual bd_size_t get_erase_size() const;

/** Get the size of an erasable block given address
*
* @param addr Address within the erasable block
* @return Size of an erasable block in bytes
* @note Must be a multiple of the program size
*/
virtual bd_size_t get_erase_size(bd_addr_t addr) const;

/** Get the value of storage when erased
*
* If get_erase_value returns a non-negative byte value, the underlying
* storage is set to that value when erased, and storage containing
* that value can be programmed without another erase.
*
* @return The value of storage when erased, or -1 if you can't
* rely on the value of erased storage
*/
virtual int get_erase_value() const;

/** Get the total size of the underlying device
*
* @return Size of the underlying device in bytes
*/
virtual bd_size_t size() const;

/** Get the BlockDevice class type.
*
* @return A string represent the BlockDevice class type.
*/
virtual const char *get_type() const;

/** Switch the Block Device power management mode
* @param pm_mode Power management mode of Block Device
* @return 0 on success, negative error code on failure
*/
virtual int switch_power_management_mode(int pm_mode);

private:
BlockDevice *_bd;
};

} // namespace mbed

// Added "using" for backwards compatibility
#ifndef MBED_NO_GLOBAL_USING_DIRECTIVE
using mbed::PowerManagementBlockDevice;
#endif

#endif

/** @}*/
201 changes: 201 additions & 0 deletions storage/blockdevice/source/PowerManagementBlockDevice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/* mbed Microcontroller Library
* Copyright (c) 2022, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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 "blockdevice/PowerManagementBlockDevice.h"
#include "platform/mbed_error.h"

#if COMPONENT_QSPIF
#include "drivers/QSPI.h"
#define QSPI_CMD_WREN 0x06
#define QSPI_CMD_RDCR0 0x15
#define QSPI_CMD_WRSR 0x01
#define QSPI_CMD_RDSR 0x05
#define QSPI_CMD_NOP 0x00
#define QSPI_CMD_DP 0xB9
#define QSPI_LH_BIT_MASK 0x02

mbed::QSPI _qspif(MBED_CONF_QSPIF_QSPI_IO0,
MBED_CONF_QSPIF_QSPI_IO1,
MBED_CONF_QSPIF_QSPI_IO2,
MBED_CONF_QSPIF_QSPI_IO3,
MBED_CONF_QSPIF_QSPI_SCK,
MBED_CONF_QSPIF_QSPI_CSN,
MBED_CONF_QSPIF_QSPI_POLARITY_MODE);
#endif

namespace mbed {

PowerManagementBlockDevice::PowerManagementBlockDevice(BlockDevice *bd)
: _bd(bd)
{
MBED_ASSERT(_bd);
}

PowerManagementBlockDevice::~PowerManagementBlockDevice()
{
deinit();
}

int PowerManagementBlockDevice::init()
{
return _bd->init();
}

int PowerManagementBlockDevice::deinit()
{
return _bd->deinit();
}

int PowerManagementBlockDevice::sync()
{
return _bd->sync();
}

int PowerManagementBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
{
return _bd->read(buffer, addr, size);
}

int PowerManagementBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
{
return _bd->program(buffer, addr, size);
}

int PowerManagementBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
return _bd->erase(addr, size);
}

bd_size_t PowerManagementBlockDevice::get_read_size() const
{
return _bd->get_read_size();
}

bd_size_t PowerManagementBlockDevice::get_program_size() const
{
return _bd->get_program_size();
}

bd_size_t PowerManagementBlockDevice::get_erase_size() const
{
return _bd->get_erase_size();
}

bd_size_t PowerManagementBlockDevice::get_erase_size(bd_addr_t addr) const
{
return _bd->get_erase_size(addr);
}

int PowerManagementBlockDevice::get_erase_value() const
{
return _bd->get_erase_value();
}

bd_size_t PowerManagementBlockDevice::size() const
{
return _bd->size();
}

const char *PowerManagementBlockDevice::get_type() const
{
if (_bd != NULL) {
return _bd->get_type();
}

return NULL;
}

int PowerManagementBlockDevice::switch_power_management_mode(int pm_mode)
{
#if COMPONENT_QSPIF
qspi_status_t status = QSPI_STATUS_OK ;
uint8_t wren_inst = QSPI_CMD_WREN;
uint8_t sr_reg[3] = {0};
uint8_t rdcr_inst = QSPI_CMD_RDCR0, wrsr_inst = QSPI_CMD_WRSR, rdsr_inst = QSPI_CMD_RDSR;
uint8_t dp_inst = 0;

if (QSPI_STATUS_OK != _qspif.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
0, QSPI_CFG_BUS_SINGLE, 0)) {
return -1;
}

if (QSPI_STATUS_OK != _qspif.command_transfer(wren_inst, -1, NULL, 0, NULL, 0)) {
return -1;
}

switch (pm_mode) {
case QSPIF_HIGH_PERFORMANCE_MODE :
if (QSPI_STATUS_OK != _qspif.command_transfer(rdsr_inst, -1, NULL, 0, (const char *)&sr_reg[0], 1)) {
return -1;
}

if (QSPI_STATUS_OK != _qspif.command_transfer(rdcr_inst, -1, NULL, 0, (const char *)&sr_reg[1], 2)) {
return -1;
}

sr_reg[2] = QSPI_LH_BIT_MASK;

if (QSPI_STATUS_OK != _qspif.command_transfer(wrsr_inst, -1, (const char *)&sr_reg[0], 3, NULL, 0)) {
return -1;
}
break;
case QSPIF_LOW_POWER_MODE :
if (QSPI_STATUS_OK != _qspif.command_transfer(rdsr_inst, -1, NULL, 0, (const char *)&sr_reg[0], 1)) {
return -1;
}

if (QSPI_STATUS_OK != _qspif.command_transfer(rdcr_inst, -1, NULL, 0, (const char *)&sr_reg[1], 2)) {
return -1;
}

sr_reg[2] = 0;

if (QSPI_STATUS_OK != _qspif.command_transfer(wrsr_inst, -1, (const char *)&sr_reg[0], 3, NULL, 0)) {
return -1;
}
break;
case QSPIF_DEEP_DOWN_MODE :
dp_inst = QSPI_CMD_DP;
if (QSPI_STATUS_OK != _qspif.command_transfer(dp_inst, -1, NULL, 0, NULL, 0)) {
return -1;
}

for (int i, k = 0; i < 10000; i++) {
k++;
}
break;
case QSPIF_STANDBY_MODE :
dp_inst = QSPI_CMD_NOP;
if (QSPI_STATUS_OK != _qspif.command_transfer(dp_inst, -1, NULL, 0, NULL, 0)) {
return -1;
}

for (int i, k = 0; i < 10000; i++) {
k++;
}
break;
default :
break;
}

return 0;
#endif
}

} // namespace mbed

/** @}*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) 2022 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)

set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../.. CACHE INTERNAL "")
set(TEST_TARGET mbed-storage-blockdevice-power_management_block_device)

include(${MBED_PATH}/tools/cmake/mbed_greentea.cmake)

project(${TEST_TARGET})

mbed_greentea_add_test(
TEST_NAME
${TEST_TARGET}
TEST_SOURCES
main.cpp
TEST_REQUIRED_LIBS
mbed-storage-blockdevice
)

Loading

0 comments on commit d332210

Please sign in to comment.