summaryrefslogtreecommitdiff
path: root/spi-uart.c
blob: 21448b9143bc15df46b3d6a7c410e5a976e9a2d7 (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
/*
 * spi-uart debug routings 
 * Copyright (C) 2008, Feng Tang <feng.tang@intel.com> Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "spi-uart.h"
#include "bootstub.h"

#define MRST_SPI_TIMEOUT	0x200000
static int spi_inited = 0;
static volatile struct mrst_spi_reg *pspi = 0;

static void spi_init()
{
	u32 ctrlr0;
	u32 *clk_reg, clk_cdiv;

	switch (*(int *)SPI_TYPE) {
	case 0:
		pspi = (struct mrst_spi_reg *)MRST_REGBASE_SPI0;
		break;
	case 1:
		pspi = (struct mrst_spi_reg *)MRST_REGBASE_SPI1;
		break;
	default:
		pspi = (struct mrst_spi_reg *)MRST_REGBASE_SPI0;
	}
	/* disable SPI controller first */
	pspi->ssienr = 0x0;

	/* set control param, 16 bits, transmit only mode */
	ctrlr0 = pspi->ctrlr0;

	ctrlr0 &= 0xfcc0;
	ctrlr0 |= (0xf | (FRF_SPI << SPI_FRF_OFFSET)
		       | (TMOD_TO << SPI_TMOD_OFFSET));
	pspi->ctrlr0 = ctrlr0;
	
	/* set a default baud rate, 115200 */
	/* get SPI controller operating freq info */
	clk_reg = (u32 *)MRST_CLK_SPI0_REG;
	clk_cdiv  = ((*clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET;
	pspi->baudr = MRST_SPI_CLK_BASE / (clk_cdiv + 1) / 115200;

	/* disable all INT for early phase */
	pspi->imr &= 0xffffff00;
	
	/* select one slave SPI device */
	pspi->ser = 0x2;

	/* enable the HW, this should be the last step for HW init */
	pspi->ssienr |= 0x1;

	spi_inited = 1;
}

/* set the ratio rate, INT */
static void max3110_write_config(void)
{
	u16 config;

	/* 115200, TM not set, no parity, 8bit word */
	config = 0xc001; 	
	pspi->dr[0] = config;
}

/* transfer char to a eligibal word and send to max3110 */
static void max3110_write_data(char c)
{
	u16 data;

	data = 0x8000 | c;
	pspi->dr[0] = data;
}

/* slave select should be called in the read/write function */
static int spi_max3110_putc(char c)
{
	unsigned int timeout;
	u32 sr;

	timeout = MRST_SPI_TIMEOUT;
	/* early putc need make sure the TX FIFO is not full*/
	while (timeout--) {
		sr = pspi->sr;
		if (!(sr & SR_TF_NOT_FULL))
			continue;
		else
			break;
	}

	if (timeout == 0xffffffff)
		return -1;

	max3110_write_data(c);

	return 0;
}

void bs_spi_printk(const char *str)
{
	if (!spi_inited) {
		spi_init();
		max3110_write_config();
	}

	if (!str)
		return;

	while (*str) {
		if (*str == '\n')
			spi_max3110_putc('\r');
		spi_max3110_putc(*str++);
	}
}