rockbox/firmware/target/mips/ingenic_x1000/sfc-x1000.h

106 lines
4.1 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2021 Aidan MacDonald
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include "clk-x1000.h"
#include "x1000/sfc.h"
/* SPI flash controller interface -- this is a low-level driver upon which
* you can build NAND/NOR flash drivers. The main function is sfc_exec(),
* used to issue commands, transfer data, etc.
*/
#define SFC_FLAG_READ 0x01 /* Read data */
#define SFC_FLAG_WRITE 0x02 /* Write data */
#define SFC_FLAG_DUMMYFIRST 0x04 /* Do dummy bits before sending address.
* Default is dummy bits after address.
*/
/* SPI transfer mode. If in doubt, check with the X1000 manual and confirm
* the transfer format is what you expect.
*/
#define SFC_MODE_STANDARD 0
#define SFC_MODE_DUAL_IN_DUAL_OUT 1
#define SFC_MODE_DUAL_IO 2
#define SFC_MODE_FULL_DUAL_IO 3
#define SFC_MODE_QUAD_IN_QUAD_OUT 4
#define SFC_MODE_QUAD_IO 5
#define SFC_MODE_FULL_QUAD_IO 6
/* Return status codes for sfc_exec() */
#define SFC_STATUS_OK 0
#define SFC_STATUS_OVERFLOW 1
#define SFC_STATUS_UNDERFLOW 2
#define SFC_STATUS_LOCKUP 3
typedef struct sfc_op {
int command; /* Command number */
int mode; /* SPI transfer mode */
int flags; /* Flags for this op */
int addr_bytes; /* Number of address bytes */
int dummy_bits; /* Number of dummy bits (yes: bits, not bytes) */
uint32_t addr_lo; /* Lower 32 bits of address */
uint32_t addr_hi; /* Upper 32 bits of address */
int data_bytes; /* Number of data bytes to read/write */
void* buffer; /* Data buffer -- MUST be word-aligned */
} sfc_op;
/* One-time driver init for mutexes/etc needed for handling interrupts.
* This can be safely called multiple times; only the first call will
* actually perform the init.
*/
extern void sfc_init(void);
/* Controller mutex -- lock before touching the driver */
extern void sfc_lock(void);
extern void sfc_unlock(void);
/* Open/close the driver. The driver must be open in order to do operations.
* Closing the driver shuts off the hardware; the driver can be re-opened at
* a later time when it's needed again.
*
* After opening the driver, you must also program a valid device configuration
* and clock rate using sfc_set_dev_conf() and sfc_set_clock().
*/
extern void sfc_open(void);
extern void sfc_close(void);
/* These functions can be called at any time while the driver is open, but
* must not be called while there is an operation in progress. It's the
* caller's job to ensure the configuration will work with the device and
* be capable of reading back data correctly.
*
* - sfc_set_dev_conf() writes its argument to the SFC_DEV_CONF register.
* - sfc_set_wp_enable() sets the state of the write-protect pin (WP).
* - sfc_set_clock() sets the controller clock frequency (in Hz).
*/
#define sfc_set_dev_conf(dev_conf) \
do { REG_SFC_DEV_CONF = (dev_conf); } while(0)
#define sfc_set_wp_enable(en) \
jz_writef(SFC_GLB, WP_EN((en) ? 1 : 0))
extern void sfc_set_clock(x1000_clk_t clksrc, uint32_t freq);
/* Execute an operation. Returns zero on success, nonzero on failure. */
extern int sfc_exec(const sfc_op* op);