Xiang Wang has uploaded this change for review.
bitbang-spi.c: support clock polarity and phase
Change-Id: I04c1dfe132d756119229b27c3cd611d1be1abc8d
Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
---
M bitbang_spi.c
1 file changed, 71 insertions(+), 41 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/55/49255/1
diff --git a/bitbang_spi.c b/bitbang_spi.c
index c402119..9003d81 100644
--- a/bitbang_spi.c
+++ b/bitbang_spi.c
@@ -2,6 +2,7 @@
* This file is part of the flashrom project.
*
* Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2021 HardenedLinux
*
* 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
@@ -21,6 +22,26 @@
#include "programmer.h"
#include "spi.h"
+/*
+ * SPI has four modes
+ *
+ * These four modes are determined by two factors.
+ * These two factors are cpol(clock polarity) and cpha(clock phase).
+ *
+ * cpol determines the sck level, when the bus is idle.
+ *
+ * There are two sck changes in a cycle.
+ * If the data transmission occurs in the first sck change then cpha=0, otherwise cpha=1.
+ *
+ * Mode = 0 -> cpol = 0, cpha = 0
+ * Mode = 1 -> cpol = 0, cpha = 1
+ * Mode = 2 -> cpol = 1, cpha = 0
+ * Mode = 3 -> cpol = 1, cpha = 1
+ */
+
+static int cpol; /* Clock Polarity */
+static int cpha; /* Clock Phase */
+
/* Note that CS# is active low, so val=0 means the chip is active. */
static void bitbang_spi_set_cs(const struct bitbang_spi_master * const master, int val)
{
@@ -44,56 +65,47 @@
master->release_bus();
}
-static void bitbang_spi_set_sck_set_mosi(const struct bitbang_spi_master * const master, int sck, int mosi)
+static void bitbang_spi_set_mosi(const struct bitbang_spi_master * const master, int mosi)
{
- if (master->set_sck_set_mosi) {
- master->set_sck_set_mosi(sck, mosi);
- return;
- }
-
- master->set_sck(sck);
master->set_mosi(mosi);
}
-static int bitbang_spi_set_sck_get_miso(const struct bitbang_spi_master * const master, int sck)
+static int bitbang_spi_get_miso(const struct bitbang_spi_master * const master)
{
- if (master->set_sck_get_miso)
- return master->set_sck_get_miso(sck);
-
- master->set_sck(sck);
return master->get_miso();
}
-static uint8_t bitbang_spi_read_byte(const struct bitbang_spi_master *master)
+static uint8_t bitbang_spi_xfer(const struct bitbang_spi_master * const master, uint8_t val)
{
uint8_t ret = 0;
- int i;
+ for (int i = 0; i < 8; i++) {
+ if (cpha == 0) {
+ bitbang_spi_set_mosi(master, (val & 0x80)==0x80);
+ val = val << 1;
+ programmer_delay(master->half_period);
+ }
+ bitbang_spi_set_sck(master, !cpol);
+ if (cpha == 0) {
+ ret = ret << 1;
+ ret |= bitbang_spi_get_miso(master);
+ programmer_delay(master->half_period);
+ }
- for (i = 7; i >= 0; i--) {
- if (i == 0)
- bitbang_spi_set_sck_set_mosi(master, 0, 0);
- else
- bitbang_spi_set_sck(master, 0);
- programmer_delay(master->half_period);
- ret <<= 1;
- ret |= bitbang_spi_set_sck_get_miso(master, 1);
- programmer_delay(master->half_period);
+ if (cpha == 1) {
+ bitbang_spi_set_mosi(master, (val & 0x80)==0x80);
+ val = val << 1;
+ programmer_delay(master->half_period);
+ }
+ bitbang_spi_set_sck(master, cpol);
+ if (cpha == 1) {
+ ret = ret << 1;
+ ret |= bitbang_spi_get_miso(master);
+ programmer_delay(master->half_period);
+ }
}
return ret;
}
-static void bitbang_spi_write_byte(const struct bitbang_spi_master *master, uint8_t val)
-{
- int i;
-
- for (i = 7; i >= 0; i--) {
- bitbang_spi_set_sck_set_mosi(master, 0, (val >> i) & 1);
- programmer_delay(master->half_period);
- bitbang_spi_set_sck(master, 1);
- programmer_delay(master->half_period);
- }
-}
-
static int bitbang_spi_send_command(const struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
@@ -107,13 +119,15 @@
* programmer to use its own SPI engine for native accesses.
*/
bitbang_spi_request_bus(master);
+ programmer_delay(master->half_period);
bitbang_spi_set_cs(master, 0);
- for (i = 0; i < writecnt; i++)
- bitbang_spi_write_byte(master, writearr[i]);
- for (i = 0; i < readcnt; i++)
- readarr[i] = bitbang_spi_read_byte(master);
+ programmer_delay(master->half_period);
- bitbang_spi_set_sck(master, 0);
+ for (i = 0; i < writecnt; i++)
+ bitbang_spi_xfer(master, writearr[i]);
+ for (i = 0; i < readcnt; i++)
+ readarr[i] = bitbang_spi_xfer(master, 0);
+
programmer_delay(master->half_period);
bitbang_spi_set_cs(master, 1);
programmer_delay(master->half_period);
@@ -155,13 +169,29 @@
return ERROR_FLASHROM_BUG;
}
+ char *mode = extract_programmer_param("mode");
+ if (mode) {
+ if (strlen(mode)) {
+ char *endptr;
+ int v = strtol(mode, &endptr, 0);
+ if (mode == endptr || v > 3 || v < 0) {
+ msg_perr("bitbang spi only work with mode 0-3\n");
+ free(mode);
+ return ERROR_FLASHROM_BUG;
+ }
+ cpol = (v >> 1) & 1;
+ cpha = (v >> 0) & 1;
+ }
+ free(mode);
+ }
+
mst.data = master;
register_spi_master(&mst);
/* Only mess with the bus if we're sure nobody else uses it. */
bitbang_spi_request_bus(master);
bitbang_spi_set_cs(master, 1);
- bitbang_spi_set_sck_set_mosi(master, 0, 0);
+ bitbang_spi_set_sck(master, cpol);
/* FIXME: Release SPI bus here and request it again for each command or
* don't release it now and only release it on programmer shutdown?
*/
To view, visit change 49255. To unsubscribe, or for help writing mail filters, visit settings.