aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/patches-4.4/081-spi-bcm53xx-add-spi_flash_read-callback-for-MMIO-bas.patch
blob: 730f41e4a5d1eeef024aa4e88368c70b605d5c85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
From a7b221d8f0d75511c5f959584712a5dd35f88a86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Mon, 18 Apr 2016 14:39:30 +0200
Subject: [PATCH] spi: bcm53xx: add spi_flash_read callback for MMIO-based
 reads
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This implements more efficient reads of SPI-attached flash content.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---

--- a/drivers/spi/spi-bcm53xx.c
+++ b/drivers/spi/spi-bcm53xx.c
@@ -10,6 +10,7 @@
 #include "spi-bcm53xx.h"
 
 #define BCM53XXSPI_MAX_SPI_BAUD	13500000	/* 216 MHz? */
+#define BCM53XXSPI_FLASH_WINDOW	SZ_32M
 
 /* The longest observed required wait was 19 ms */
 #define BCM53XXSPI_SPE_TIMEOUT_MS	80
@@ -17,8 +18,10 @@
 struct bcm53xxspi {
 	struct bcma_device *core;
 	struct spi_master *master;
+	void __iomem *mmio_base;
 
 	size_t read_offset;
+	bool bspi;				/* Boot SPI mode with memory mapping */
 };
 
 static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
@@ -32,6 +35,50 @@ static inline void bcm53xxspi_write(stru
 	bcma_write32(b53spi->core, offset, value);
 }
 
+static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi)
+{
+	struct device *dev = &b53spi->core->dev;
+	unsigned long deadline;
+	u32 tmp;
+
+	if (!b53spi->bspi)
+		return;
+
+	tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
+	if (tmp & 0x1)
+		return;
+
+	deadline = jiffies + usecs_to_jiffies(200);
+	do {
+		tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS);
+		if (!(tmp & 0x1)) {
+			bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL,
+					 0x1);
+			ndelay(200);
+			b53spi->bspi = false;
+			return;
+		}
+		udelay(1);
+	} while (!time_after_eq(jiffies, deadline));
+
+	dev_warn(dev, "Timeout disabling BSPI\n");
+}
+
+static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi)
+{
+	u32 tmp;
+
+	if (b53spi->bspi)
+		return;
+
+	tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
+	if (!(tmp & 0x1))
+		return;
+
+	bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0);
+	b53spi->bspi = true;
+}
+
 static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
 {
 	/* Do some magic calculation based on length and buad. Add 10% and 1. */
@@ -176,6 +223,8 @@ static int bcm53xxspi_transfer_one(struc
 	u8 *buf;
 	size_t left;
 
+	bcm53xxspi_disable_bspi(b53spi);
+
 	if (t->tx_buf) {
 		buf = (u8 *)t->tx_buf;
 		left = t->len;
@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struc
 	return 0;
 }
 
+static int bcm53xxspi_flash_read(struct spi_device *spi,
+				 struct spi_flash_read_message *msg)
+{
+	struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master);
+	int ret = 0;
+
+	if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW)
+		return -EINVAL;
+
+	bcm53xxspi_enable_bspi(b53spi);
+	memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
+	msg->retlen = msg->len;
+
+	return ret;
+}
+
 /**************************************************
  * BCMA
  **************************************************/
@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcm
 
 static int bcm53xxspi_bcma_probe(struct bcma_device *core)
 {
+	struct device *dev = &core->dev;
 	struct bcm53xxspi *b53spi;
 	struct spi_master *master;
 	int err;
@@ -231,7 +297,7 @@ static int bcm53xxspi_bcma_probe(struct
 		return -ENOTSUPP;
 	}
 
-	master = spi_alloc_master(&core->dev, sizeof(*b53spi));
+	master = spi_alloc_master(dev, sizeof(*b53spi));
 	if (!master)
 		return -ENOMEM;
 
@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct
 	b53spi->master = master;
 	b53spi->core = core;
 
+	if (core->addr_s[0])
+		b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0],
+						 BCM53XXSPI_FLASH_WINDOW);
+	b53spi->bspi = true;
+	bcm53xxspi_disable_bspi(b53spi);
+
 	master->transfer_one = bcm53xxspi_transfer_one;
+	if (b53spi->mmio_base)
+		master->spi_flash_read = bcm53xxspi_flash_read;
 
 	bcma_set_drvdata(core, b53spi);
 
-	err = devm_spi_register_master(&core->dev, master);
+	err = devm_spi_register_master(dev, master);
 	if (err) {
 		spi_master_put(master);
 		bcma_set_drvdata(core, NULL);