Module Name:    src
Committed By:   rkujawa
Date:           Wed May  1 12:17:17 UTC 2013

Added Files:
        src/sys/dev/marvell: mvspi.c mvspireg.h

Log Message:
Add support for Marvell's SPI controller as found on Armada XP.

Obtained from Semihalf.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/dev/marvell/mvspi.c \
    src/sys/dev/marvell/mvspireg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/sys/dev/marvell/mvspi.c
diff -u /dev/null src/sys/dev/marvell/mvspi.c:1.1
--- /dev/null	Wed May  1 12:17:17 2013
+++ src/sys/dev/marvell/mvspi.c	Wed May  1 12:17:17 2013
@@ -0,0 +1,368 @@
+/*******************************************************************************
+Copyright (C) Marvell International Ltd. and its affiliates
+
+Developed by Semihalf
+
+********************************************************************************
+Marvell BSD License
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    *   Redistributions of source code must retain the above copyright notice,
+            this list of conditions and the following disclaimer.
+
+    *   Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+    *   Neither the name of Marvell nor the names of its contributors may be
+        used to endorse or promote products derived from this software without
+        specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/*
+ * Transfer mechanism extracted from arspi.c corresponding with the lines 
+ * 254-262 in this file.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+
+#include <dev/spi/spivar.h>
+
+#include <dev/marvell/mvspireg.h>
+#include <dev/marvell/marvellvar.h>
+
+#include "locators.h"
+
+extern uint32_t mvTclk;
+
+struct mvspi_softc {
+	struct device		sc_dev;
+	struct spi_controller	sc_spi;
+	void			*sc_ih;
+	bool			sc_interrupts;
+
+	struct spi_transfer	*sc_transfer;
+	struct spi_chunk	*sc_wchunk;	/* For partial writes */
+	struct spi_transq	sc_transq;
+	bus_space_tag_t		sc_st;
+	bus_space_handle_t	sc_sh;
+	bus_size_t		sc_size;
+};
+
+int mvspi_match(struct device *, struct cfdata *, void *);
+void mvspi_attach(struct device *, struct device *, void *);
+/* SPI service routines */
+int mvspi_configure(void *, int, int, int);
+int mvspi_transfer(void *, struct spi_transfer *);
+/* Internal support */
+void mvspi_sched(struct mvspi_softc *);
+void mvspi_assert(struct mvspi_softc *sc);
+void mvspi_deassert(struct mvspi_softc *sc);
+
+#define	GETREG(sc, x)					\
+	bus_space_read_4(sc->sc_st, sc->sc_sh, x)
+#define	PUTREG(sc, x, v)				\
+	bus_space_write_4(sc->sc_st, sc->sc_sh, x, v)
+
+/* Attach structure */
+CFATTACH_DECL_NEW(mvspi_mbus, sizeof(struct mvspi_softc),
+    mvspi_match, mvspi_attach, NULL, NULL);
+
+int
+mvspi_match(struct device *parent, struct cfdata *cf, void *aux)
+{
+	struct marvell_attach_args *mva = aux;
+
+	if (strcmp(mva->mva_name, cf->cf_name) != 0)
+		return 0;
+	if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
+	    mva->mva_irq == MVA_IRQ_DEFAULT)
+		return 0;
+
+	mva->mva_size = MVSPI_SIZE;
+	return 1;
+}
+
+void
+mvspi_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct mvspi_softc *sc =  device_private(self);
+  	struct marvell_attach_args *mva = aux;
+	struct spibus_attach_args sba;
+	int ctl;
+
+	aprint_normal(": Marvell SPI controller\n");
+
+	/*
+	 * Map registers.
+	 */
+	sc->sc_st = mva->mva_iot;
+	sc->sc_size = mva->mva_size;
+	
+	if (bus_space_subregion(sc->sc_st, mva->mva_ioh, mva->mva_offset,
+	    mva->mva_size, &sc->sc_sh)) {
+		aprint_error_dev(self, "Cannot map registers\n");
+		return;
+	}
+
+	/*
+	 * Initialize hardware.
+	 */
+	ctl = GETREG(sc, MVSPI_INTCONF_REG);
+
+	ctl &= MVSPI_DIRHS_MASK;
+	ctl &= MVSPI_1BYTE_MASK;
+
+	PUTREG(sc, MVSPI_INTCONF_REG, ctl),
+
+	/*
+	 * Initialize SPI controller.
+	 */
+	sc->sc_spi.sct_cookie = sc;
+	sc->sc_spi.sct_configure = mvspi_configure;
+	sc->sc_spi.sct_transfer = mvspi_transfer;
+	sc->sc_spi.sct_nslaves = 1;
+
+	/*
+	 * Initialize the queue.
+	 */
+	spi_transq_init(&sc->sc_transq);
+
+	/*
+	 * Initialize and attach bus attach.
+	 */
+	sba.sba_controller = &sc->sc_spi;
+	(void) config_found_ia(self, "spibus", &sba, spibus_print);
+}
+    
+int
+mvspi_configure(void *cookie, int slave, int mode, int speed)
+{
+	struct mvspi_softc *sc = cookie;
+	uint32_t ctl = 0, spr, sppr;
+	uint32_t divider;
+	uint32_t best_spr = 0, best_sppr = 0;
+	uint32_t best_sppr0, best_spprhi;
+	uint8_t exact_match = 0;
+	uint32_t min_baud_offset = 0xFFFFFFFF;
+	
+	if (slave < 0 || slave > 7)
+		return EINVAL;
+
+	switch(mode) {
+		case SPI_MODE_0:
+			ctl &= ~(MVSPI_CPOL_MASK);
+			/* In boards documentation, CPHA is inverted */
+			ctl &= MVSPI_CPHA_MASK;
+			break;
+		case SPI_MODE_1:
+			ctl |= MVSPI_CPOL_MASK;
+			ctl &= MVSPI_CPHA_MASK;
+			break;
+		case SPI_MODE_2:
+			ctl &= ~(MVSPI_CPOL_MASK);
+			ctl |= ~(MVSPI_CPHA_MASK);
+			break;
+		case SPI_MODE_3:
+			ctl |= MVSPI_CPOL_MASK;
+			ctl |= ~(MVSPI_CPHA_MASK);
+			break;
+		default:
+			return EINVAL;
+	}
+
+	/* Find the best prescale configuration - less or equal:
+	 * SPI actual frecuency = core_clk / (SPR * (2 ^ SPPR))
+	 * Try to find the minimal SPR and SPPR values that offer
+	 * the best prescale config.
+	 *
+	 */
+	for (spr = 1; spr <= MVSPI_SPR_MAXVALUE; spr++) {
+		for (sppr = 0; sppr <= MVSPI_SPPR_MAXVALUE; sppr++) {
+			divider = spr * (1 << sppr);
+			/* Check for higher - irrelevant */
+			if ((mvTclk / divider) > speed)
+				continue;
+
+			/* Check for exact fit */
+			if ((mvTclk / divider) == speed) {
+				best_spr = spr;
+				best_sppr = sppr;
+				exact_match = 1;
+				break;
+			}
+
+			/* Check if this is better than the previous one */
+			if ((speed - (mvTclk / divider)) < min_baud_offset) {
+				min_baud_offset = (speed - (mvTclk / divider));
+				best_spr = spr;
+				best_sppr = sppr;
+			}
+		}
+
+		if (exact_match == 1)
+			break;
+	}
+
+	if (best_spr == 0) {
+		printf("%s ERROR: SPI baud rate prescale error!\n", __func__);
+		return -1;
+	}
+
+	ctl &= ~(MVSPI_SPR_MASK);
+	ctl &= ~(MVSPI_SPPR_MASK);
+	ctl |= best_spr;
+
+	best_spprhi = best_sppr & MVSPI_SPPRHI_MASK;
+	best_spprhi = best_spprhi << 5;
+
+	ctl |= best_spprhi;
+
+	best_sppr0 = best_sppr & MVSPI_SPPR0_MASK;
+	best_sppr0 = best_sppr0 << 4;
+
+	ctl |= best_sppr0;
+
+	PUTREG(sc, MVSPI_INTCONF_REG, ctl);
+
+	return 0;
+}
+
+int
+mvspi_transfer(void *cookie, struct spi_transfer *st)
+{
+	struct mvspi_softc *sc = cookie;
+	int s, er;
+
+	er = 0;
+
+	s = splbio();
+	spi_transq_enqueue(&sc->sc_transq, st);
+	if (sc->sc_transfer == NULL) {
+		mvspi_sched(sc);
+	}
+	splx(s);
+	return 0;
+}
+
+void
+mvspi_assert(struct mvspi_softc *sc)
+{
+	int ctl;
+	
+	if (sc->sc_transfer->st_slave < 0 && sc->sc_transfer->st_slave > 7) {
+		printf("%s ERROR: Slave number %d not valid!\n",  __func__, sc->sc_transfer->st_slave);
+		return;
+	} else
+		/* Enable appropriate CSn according to its slave number */
+		PUTREG(sc, MVSPI_CTRL_REG, (sc->sc_transfer->st_slave << 2));
+
+	/* Enable CSnAct */
+	ctl = GETREG(sc, MVSPI_CTRL_REG);
+	ctl |= MVSPI_CSNACT_MASK;
+	PUTREG(sc, MVSPI_CTRL_REG, ctl);
+}
+
+void
+mvspi_deassert(struct mvspi_softc *sc)
+{
+	int ctl = GETREG(sc, MVSPI_CTRL_REG);
+	ctl &= ~(MVSPI_CSNACT_MASK);
+	PUTREG(sc, MVSPI_CTRL_REG, ctl);
+}
+
+void
+mvspi_sched(struct mvspi_softc *sc)
+{
+	struct spi_transfer *st;
+	struct spi_chunk *chunk;
+	int i, j, ctl;
+	uint8_t byte;
+	int ready = FALSE;
+
+	for (;;) {
+		if ((st = sc->sc_transfer) == NULL) {
+			if ((st = spi_transq_first(&sc->sc_transq)) == NULL) {
+				/* No work left to do */
+				break;
+			}
+			spi_transq_dequeue(&sc->sc_transq);
+			sc->sc_transfer = st;
+		}
+
+		chunk = st->st_chunks;
+
+		mvspi_assert(sc);
+
+		do {
+			for (i = chunk->chunk_wresid; i > 0; i--) {
+				/* First clear the ready bit */
+				ctl = GETREG(sc, MVSPI_CTRL_REG);
+				ctl &= ~(MVSPI_CR_SMEMRDY);
+				PUTREG(sc, MVSPI_CTRL_REG, ctl);
+
+				if (chunk->chunk_wptr){
+					byte = *chunk->chunk_wptr;
+					chunk->chunk_wptr++;
+				} else
+					byte = MVSPI_DUMMY_BYTE;
+
+				/* Transmit data */
+				PUTREG(sc, MVSPI_DATAOUT_REG, byte);
+
+				/* Wait with timeout for memory ready */
+				for (j = 0; j < MVSPI_WAIT_RDY_MAX_LOOP; j++) {
+					if (GETREG(sc, MVSPI_CTRL_REG) &
+						MVSPI_CR_SMEMRDY) {
+						ready = TRUE;
+						break;
+					}
+
+				}
+
+				if (!ready) {
+					mvspi_deassert(sc);
+					spi_done(st, EBUSY);
+					return;
+				}
+
+				/* Check that the RX data is needed */
+				if (chunk->chunk_rptr) {
+					*chunk->chunk_rptr =
+						GETREG(sc, MVSPI_DATAIN_REG);
+					chunk->chunk_rptr++;
+
+				}
+
+			}
+
+			chunk = chunk->chunk_next;
+
+		} while (chunk != NULL);
+
+		mvspi_deassert(sc);
+
+		spi_done(st, 0);
+		sc->sc_transfer = NULL;
+
+
+		break;
+	}
+}
Index: src/sys/dev/marvell/mvspireg.h
diff -u /dev/null src/sys/dev/marvell/mvspireg.h:1.1
--- /dev/null	Wed May  1 12:17:17 2013
+++ src/sys/dev/marvell/mvspireg.h	Wed May  1 12:17:17 2013
@@ -0,0 +1,80 @@
+/*******************************************************************************
+Copyright (C) Marvell International Ltd. and its affiliates
+
+Developed by Semihalf
+
+********************************************************************************
+Marvell BSD License
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    *   Redistributions of source code must retain the above copyright notice,
+            this list of conditions and the following disclaimer.
+
+    *   Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+    *   Neither the name of Marvell nor the names of its contributors may be
+        used to endorse or promote products derived from this software without
+        specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "opt_mvsoc.h"
+
+#ifndef _MVSPIREG_H_
+#define _MVSPIREG_H_
+
+#define		MVSPI_SIZE			0x50		/* Size of MVSPI */
+
+/* Definition of registers */
+#define		MVSPI_CTRL_REG			0x00		/* MVSPI Control Register */
+#define		MVSPI_INTCONF_REG		0x04		/* MVSPI Interface Configuration Register */
+#define		MVSPI_DATAOUT_REG		0x08		/* MVSPI Data Out Register */
+#define		MVSPI_DATAIN_REG		0x0C		/* MVSPI Data In Register */
+#define		MVSPI_IRQCAUSE_REG		0x10		/* MVSPI Interrupt Cause Register */
+#define		MVSPI_IRQMASK_REG		0x14		/* MVSPI Interrupt Mask Register */
+#define		MVSPI_TIMEPAR1_REG		0x18		/* MVSPI Timing Parameters 1 Register*/
+#define		MVSPI_TIMEPAR2_REG		0x1C		/* MVSPI Timing Parameters 2 Register */
+#define		MVSPI_DIRWRITE_REG		0x20		/* MVSPI Direct Write Configuration Register*/ 
+#define		MVSPI_DIRWRITEHD_REG		0x24		/* MVSPI Direct Write Header Register */
+#define		MVSPI_DIRREADHD_REG		0x28		/* MVSPI Direct Read Header Register */
+#define		MVSPI_CSADRDEC_REG		0x2C		/* MVSPI CS Address Decode Register */
+#define		MVSPI_CSnTIMPAR_REG		0x30		/* MVSPI CSn Timing Parameters Register */
+#define		MVSPI_CNTVER_REG		0x50		/* MVSPI Controller Version Register */
+
+/* Masks */
+#define		MVSPI_CPOL_MASK			0x0800		/* CPOL bit = 1 */
+#define		MVSPI_CPHA_MASK			0x1000		/* CPHA bit = 1 */
+#define		MVSPI_DIRHS_MASK		0xFBFF		/* SPI Direct Read High Speed Transaction Mask */
+#define		MVSPI_1BYTE_MASK		0xFFDF		/* Number of bits in each I/O transfer Mask */
+#define		MVSPI_SPR_MASK			0x0007		/* SPR field mask */
+#define		MVSPI_SPPR_MASK			0x00D0		/* SPPR field mask */
+#define		MVSPI_SPPRHI_MASK		0x00C0		/* SPPR_HI field mask */
+#define		MVSPI_SPPR0_MASK		0x0010		/* SPPR0 field mask */
+#define		MVSPI_CSNACT_MASK		0x0001		/* CSn transfer acknowledge bit */
+
+#define		MVSPI_CR_SMEMRDY		0x0002		/* MVSPI Control Register Serial Memory Data Transfer Ready */
+
+#define		MVSPI_DUMMY_BYTE		0xFF		/* Dummy byte */
+
+#define		MVSPI_WAIT_RDY_MAX_LOOP		100000		/* Transfer timeout threshold */
+#define		MVSPI_SPR_MAXVALUE		15		/* Maximum value for SPR coeficient */
+#define		MVSPI_SPPR_MAXVALUE		7		/* Maximum value for SPPR coeficient */
+
+#endif		/* _MVSPIREG_H_ */

Reply via email to