spi: Fixes for v6.10
This pull request fixes two regressions that have been bubbling along for a large part of this release. One is a revert of the multi mode support for the OMAP SPI controller, this introduced regressions on a number of systems and while there has been progress on fixing those we've not got something that works for everyone yet so let's just drop the change for now. The other is a series of fixes from David Lechner for his recent message optimisation work, this interacted badly with spi-mux which is altogether too clever with recursive use of the bus and creates situations that hadn't been considered. There are also a couple of small driver specific fixes, including one more patch from David for sleep duration calculations in the AXI driver. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmaP8BoACgkQJNaLcl1U h9CaqAf/clXigdOnaNCJhwMKV4eGaa1cZPNMAnrS0r9/T2gs/gfm3Pt5vKGQnMph LizSMb9cyGyMrfRdqjSZknYNXur4JW7/g1+HuFlGfYKroWeqpUi+8Ye+mm/39qT5 T5yiihv6izh3hfDya2R+x6xITi0n+0j/KjtIWGDRkEOPQqeSHjvg19nvkuT/xK8U kqML/tCibAMo+4c/PCSjZ3q49EiYPH595WC6EfKE9ijUKvgRGNF7bFbav4CiJB8/ pESPqtPXHsgUITyQGPafttCdt3xl/pPDDRaMztA5rP/1s6gmjvFF4zq5/ztTceyE i2F8eK6JV3Jf/bHY4V0OW0bam2CEKA== =kPL9 -----END PGP SIGNATURE----- Merge tag 'spi-fix-v6.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "This fixes two regressions that have been bubbling along for a large part of this release. One is a revert of the multi mode support for the OMAP SPI controller, this introduced regressions on a number of systems and while there has been progress on fixing those we've not got something that works for everyone yet so let's just drop the change for now. The other is a series of fixes from David Lechner for his recent message optimisation work, this interacted badly with spi-mux which is altogether too clever with recursive use of the bus and creates situations that hadn't been considered. There are also a couple of small driver specific fixes, including one more patch from David for sleep duration calculations in the AXI driver" * tag 'spi-fix-v6.10-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: mux: set ctlr->bits_per_word_mask spi: add defer_optimize_message controller flag spi: don't unoptimize message in spi_async() spi: omap2-mcspi: Revert multi mode support spi: davinci: Unset POWERDOWN bit when releasing resources spi: axi-spi-engine: fix sleep calculation spi: imx: Don't expect DMA for i.MX{25,35,50,51,53} cspi devices
This commit is contained in:
commit
8a18fda0fe
@ -164,16 +164,20 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
|
||||
}
|
||||
|
||||
static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
|
||||
int delay_ns, u32 sclk_hz)
|
||||
int delay_ns, int inst_ns, u32 sclk_hz)
|
||||
{
|
||||
unsigned int t;
|
||||
|
||||
/* negative delay indicates error, e.g. from spi_delay_to_ns() */
|
||||
if (delay_ns <= 0)
|
||||
/*
|
||||
* Negative delay indicates error, e.g. from spi_delay_to_ns(). And if
|
||||
* delay is less that the instruction execution time, there is no need
|
||||
* for an extra sleep instruction since the instruction execution time
|
||||
* will already cover the required delay.
|
||||
*/
|
||||
if (delay_ns < 0 || delay_ns <= inst_ns)
|
||||
return;
|
||||
|
||||
/* rounding down since executing the instruction adds a couple of ticks delay */
|
||||
t = DIV_ROUND_DOWN_ULL((u64)delay_ns * sclk_hz, NSEC_PER_SEC);
|
||||
t = DIV_ROUND_UP_ULL((u64)(delay_ns - inst_ns) * sclk_hz, NSEC_PER_SEC);
|
||||
while (t) {
|
||||
unsigned int n = min(t, 256U);
|
||||
|
||||
@ -220,10 +224,16 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
|
||||
struct spi_device *spi = msg->spi;
|
||||
struct spi_controller *host = spi->controller;
|
||||
struct spi_transfer *xfer;
|
||||
int clk_div, new_clk_div;
|
||||
int clk_div, new_clk_div, inst_ns;
|
||||
bool keep_cs = false;
|
||||
u8 bits_per_word = 0;
|
||||
|
||||
/*
|
||||
* Take into account instruction execution time for more accurate sleep
|
||||
* times, especially when the delay is small.
|
||||
*/
|
||||
inst_ns = DIV_ROUND_UP(NSEC_PER_SEC, host->max_speed_hz);
|
||||
|
||||
clk_div = 1;
|
||||
|
||||
spi_engine_program_add_cmd(p, dry,
|
||||
@ -252,7 +262,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
|
||||
|
||||
spi_engine_gen_xfer(p, dry, xfer);
|
||||
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
|
||||
xfer->effective_speed_hz);
|
||||
inst_ns, xfer->effective_speed_hz);
|
||||
|
||||
if (xfer->cs_change) {
|
||||
if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
|
||||
@ -262,7 +272,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
|
||||
spi_engine_gen_cs(p, dry, spi, false);
|
||||
|
||||
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(
|
||||
&xfer->cs_change_delay, xfer),
|
||||
&xfer->cs_change_delay, xfer), inst_ns,
|
||||
xfer->effective_speed_hz);
|
||||
|
||||
if (!list_next_entry(xfer, transfer_list)->cs_off)
|
||||
|
@ -984,6 +984,9 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
free_dma:
|
||||
/* This bit needs to be cleared to disable dpsi->clk */
|
||||
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
|
||||
|
||||
if (dspi->dma_rx) {
|
||||
dma_release_channel(dspi->dma_rx);
|
||||
dma_release_channel(dspi->dma_tx);
|
||||
@ -1013,6 +1016,9 @@ static void davinci_spi_remove(struct platform_device *pdev)
|
||||
|
||||
spi_bitbang_stop(&dspi->bitbang);
|
||||
|
||||
/* This bit needs to be cleared to disable dpsi->clk */
|
||||
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
|
||||
|
||||
if (dspi->dma_rx) {
|
||||
dma_release_channel(dspi->dma_rx);
|
||||
dma_release_channel(dspi->dma_tx);
|
||||
|
@ -1050,7 +1050,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
|
||||
.rx_available = mx31_rx_available,
|
||||
.reset = mx31_reset,
|
||||
.fifo_size = 8,
|
||||
.has_dmamode = true,
|
||||
.has_dmamode = false,
|
||||
.dynamic_burst = false,
|
||||
.has_targetmode = false,
|
||||
.devtype = IMX35_CSPI,
|
||||
|
@ -158,12 +158,14 @@ static int spi_mux_probe(struct spi_device *spi)
|
||||
/* supported modes are the same as our parent's */
|
||||
ctlr->mode_bits = spi->controller->mode_bits;
|
||||
ctlr->flags = spi->controller->flags;
|
||||
ctlr->bits_per_word_mask = spi->controller->bits_per_word_mask;
|
||||
ctlr->transfer_one_message = spi_mux_transfer_one_message;
|
||||
ctlr->setup = spi_mux_setup;
|
||||
ctlr->num_chipselect = mux_control_states(priv->mux);
|
||||
ctlr->bus_num = -1;
|
||||
ctlr->dev.of_node = spi->dev.of_node;
|
||||
ctlr->must_async = true;
|
||||
ctlr->defer_optimize_message = true;
|
||||
|
||||
ret = devm_spi_register_controller(&spi->dev, ctlr);
|
||||
if (ret)
|
||||
|
@ -1277,24 +1277,11 @@ static int omap2_mcspi_prepare_message(struct spi_controller *ctlr,
|
||||
|
||||
/*
|
||||
* Check if this transfer contains only one word;
|
||||
* OR contains 1 to 4 words, with bits_per_word == 8 and no delay between each word
|
||||
* OR contains 1 to 2 words, with bits_per_word == 16 and no delay between each word
|
||||
*
|
||||
* If one of the two last case is true, this also change the bits_per_word of this
|
||||
* transfer to make it a bit faster.
|
||||
* It's not an issue to change the bits_per_word here even if the multi-mode is not
|
||||
* applicable for this message, the signal on the wire will be the same.
|
||||
*/
|
||||
if (bits_per_word < 8 && tr->len == 1) {
|
||||
/* multi-mode is applicable, only one word (1..7 bits) */
|
||||
} else if (tr->word_delay.value == 0 && bits_per_word == 8 && tr->len <= 4) {
|
||||
/* multi-mode is applicable, only one "bigger" word (8,16,24,32 bits) */
|
||||
tr->bits_per_word = tr->len * bits_per_word;
|
||||
} else if (tr->word_delay.value == 0 && bits_per_word == 16 && tr->len <= 2) {
|
||||
/* multi-mode is applicable, only one "bigger" word (16,32 bits) */
|
||||
tr->bits_per_word = tr->len * bits_per_word / 2;
|
||||
} else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) {
|
||||
/* multi-mode is applicable, only one word (9..15,17..32 bits) */
|
||||
/* multi-mode is applicable, only one word (8..32 bits) */
|
||||
} else {
|
||||
/* multi-mode is not applicable: more than one word in the transfer */
|
||||
mcspi->use_multi_mode = false;
|
||||
|
@ -2151,7 +2151,8 @@ static void __spi_unoptimize_message(struct spi_message *msg)
|
||||
*/
|
||||
static void spi_maybe_unoptimize_message(struct spi_message *msg)
|
||||
{
|
||||
if (!msg->pre_optimized && msg->optimized)
|
||||
if (!msg->pre_optimized && msg->optimized &&
|
||||
!msg->spi->controller->defer_optimize_message)
|
||||
__spi_unoptimize_message(msg);
|
||||
}
|
||||
|
||||
@ -4294,6 +4295,11 @@ static int __spi_optimize_message(struct spi_device *spi,
|
||||
static int spi_maybe_optimize_message(struct spi_device *spi,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
if (spi->controller->defer_optimize_message) {
|
||||
msg->spi = spi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msg->pre_optimized)
|
||||
return 0;
|
||||
|
||||
@ -4324,6 +4330,13 @@ int spi_optimize_message(struct spi_device *spi, struct spi_message *msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Pre-optimization is not supported and optimization is deferred e.g.
|
||||
* when using spi-mux.
|
||||
*/
|
||||
if (spi->controller->defer_optimize_message)
|
||||
return 0;
|
||||
|
||||
ret = __spi_optimize_message(spi, msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -4350,6 +4363,9 @@ EXPORT_SYMBOL_GPL(spi_optimize_message);
|
||||
*/
|
||||
void spi_unoptimize_message(struct spi_message *msg)
|
||||
{
|
||||
if (msg->spi->controller->defer_optimize_message)
|
||||
return;
|
||||
|
||||
__spi_unoptimize_message(msg);
|
||||
msg->pre_optimized = false;
|
||||
}
|
||||
@ -4432,8 +4448,6 @@ int spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
|
||||
|
||||
spi_maybe_unoptimize_message(message);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_async);
|
||||
|
@ -533,6 +533,9 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
|
||||
* @queue_empty: signal green light for opportunistically skipping the queue
|
||||
* for spi_sync transfers.
|
||||
* @must_async: disable all fast paths in the core
|
||||
* @defer_optimize_message: set to true if controller cannot pre-optimize messages
|
||||
* and needs to defer the optimization step until the message is actually
|
||||
* being transferred
|
||||
*
|
||||
* Each SPI controller can communicate with one or more @spi_device
|
||||
* children. These make a small bus, sharing MOSI, MISO and SCK signals
|
||||
@ -776,6 +779,7 @@ struct spi_controller {
|
||||
/* Flag for enabling opportunistic skipping of the queue in spi_sync */
|
||||
bool queue_empty;
|
||||
bool must_async;
|
||||
bool defer_optimize_message;
|
||||
};
|
||||
|
||||
static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
|
||||
|
Loading…
Reference in New Issue
Block a user