summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/serial/Kconfig4
-rw-r--r--drivers/serial/serial_stm32x7.c84
-rw-r--r--drivers/serial/serial_stm32x7.h71
-rw-r--r--drivers/video/Kconfig8
-rw-r--r--drivers/video/vidconsole-uclass.c205
-rw-r--r--drivers/video/video-uclass.c4
7 files changed, 312 insertions, 66 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 24b4eadd2a..940508364a 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -386,7 +386,7 @@ config GENERIC_ATMEL_MCI
config STM32_SDMMC2
bool "STMicroelectronics STM32H7 SD/MMC Host Controller support"
- depends on DM_MMC && BLK && OF_CONTROL && DM_MMC_OPS
+ depends on DM_MMC && BLK && OF_CONTROL
help
This selects support for the SD/MMC controller on STM32H7 SoCs.
If you have a board based on such a SoC and with a SD/MMC slot,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 9bf2e26e9d..7c54a49bb3 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -531,9 +531,9 @@ config STI_ASC_SERIAL
config STM32X7_SERIAL
bool "STMicroelectronics STM32 SoCs on-chip UART"
- depends on DM_SERIAL && (STM32F7 || STM32H7)
+ depends on DM_SERIAL && (STM32F4 || STM32F7 || STM32H7)
help
- If you have a machine based on a STM32 F7 or H7 SoC you can
+ If you have a machine based on a STM32 F4, F7 or H7 SoC you can
enable its onboard serial ports, say Y to this option.
If unsure, say N.
diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c
index 2f4eafa885..a5d529cab2 100644
--- a/drivers/serial/serial_stm32x7.c
+++ b/drivers/serial/serial_stm32x7.c
@@ -17,71 +17,81 @@ DECLARE_GLOBAL_DATA_PTR;
static int stm32_serial_setbrg(struct udevice *dev, int baudrate)
{
- struct stm32x7_serial_platdata *plat = dev->platdata;
- struct stm32_usart *const usart = plat->base;
+ struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
+ bool stm32f4 = plat->uart_info->stm32f4;
+ fdt_addr_t base = plat->base;
u32 int_div, mantissa, fraction, oversampling;
int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate);
if (int_div < 16) {
oversampling = 8;
- setbits_le32(&usart->cr1, USART_CR1_OVER8);
+ setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8);
} else {
oversampling = 16;
- clrbits_le32(&usart->cr1, USART_CR1_OVER8);
+ clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8);
}
mantissa = (int_div / oversampling) << USART_BRR_M_SHIFT;
fraction = int_div % oversampling;
- writel(mantissa | fraction, &usart->brr);
+ writel(mantissa | fraction, base + BRR_OFFSET(stm32f4));
return 0;
}
static int stm32_serial_getc(struct udevice *dev)
{
- struct stm32x7_serial_platdata *plat = dev->platdata;
- struct stm32_usart *const usart = plat->base;
+ struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
+ bool stm32f4 = plat->uart_info->stm32f4;
+ fdt_addr_t base = plat->base;
- if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0)
+ if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_RXNE) == 0)
return -EAGAIN;
- return readl(&usart->rd_dr);
+ return readl(base + RDR_OFFSET(stm32f4));
}
static int stm32_serial_putc(struct udevice *dev, const char c)
{
- struct stm32x7_serial_platdata *plat = dev->platdata;
- struct stm32_usart *const usart = plat->base;
+ struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
+ bool stm32f4 = plat->uart_info->stm32f4;
+ fdt_addr_t base = plat->base;
- if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0)
+ if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_TXE) == 0)
return -EAGAIN;
- writel(c, &usart->tx_dr);
+ writel(c, base + TDR_OFFSET(stm32f4));
return 0;
}
static int stm32_serial_pending(struct udevice *dev, bool input)
{
- struct stm32x7_serial_platdata *plat = dev->platdata;
- struct stm32_usart *const usart = plat->base;
+ struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
+ bool stm32f4 = plat->uart_info->stm32f4;
+ fdt_addr_t base = plat->base;
if (input)
- return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0;
+ return readl(base + ISR_OFFSET(stm32f4)) &
+ USART_SR_FLAG_RXNE ? 1 : 0;
else
- return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1;
+ return readl(base + ISR_OFFSET(stm32f4)) &
+ USART_SR_FLAG_TXE ? 0 : 1;
}
static int stm32_serial_probe(struct udevice *dev)
{
- struct stm32x7_serial_platdata *plat = dev->platdata;
- struct stm32_usart *const usart = plat->base;
-
-#ifdef CONFIG_CLK
- int ret;
+ struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
struct clk clk;
+ fdt_addr_t base = plat->base;
+ int ret;
+ bool stm32f4;
+ u8 uart_enable_bit;
+
+ plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev);
+ stm32f4 = plat->uart_info->stm32f4;
+ uart_enable_bit = plat->uart_info->uart_enable_bit;
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
@@ -92,7 +102,6 @@ static int stm32_serial_probe(struct udevice *dev)
dev_err(dev, "failed to enable clock\n");
return ret;
}
-#endif
plat->clock_rate = clk_get_rate(&clk);
if (plat->clock_rate < 0) {
@@ -100,37 +109,36 @@ static int stm32_serial_probe(struct udevice *dev)
return plat->clock_rate;
};
- /* Disable usart-> disable overrun-> enable usart */
- clrbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
- setbits_le32(&usart->cr3, USART_CR3_OVRDIS);
- setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
+ /* Disable uart-> disable overrun-> enable uart */
+ clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE |
+ BIT(uart_enable_bit));
+ if (plat->uart_info->has_overrun_disable)
+ setbits_le32(base + CR3_OFFSET(stm32f4), USART_CR3_OVRDIS);
+ if (plat->uart_info->has_fifo)
+ setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_FIFOEN);
+ setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE |
+ BIT(uart_enable_bit));
return 0;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
static const struct udevice_id stm32_serial_id[] = {
- {.compatible = "st,stm32f7-usart"},
- {.compatible = "st,stm32f7-uart"},
- {.compatible = "st,stm32h7-usart"},
- {.compatible = "st,stm32h7-uart"},
+ { .compatible = "st,stm32-uart", .data = (ulong)&stm32f4_info},
+ { .compatible = "st,stm32f7-uart", .data = (ulong)&stm32f7_info},
+ { .compatible = "st,stm32h7-uart", .data = (ulong)&stm32h7_info},
{}
};
static int stm32_serial_ofdata_to_platdata(struct udevice *dev)
{
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = devfdt_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
+ plat->base = devfdt_get_addr(dev);
+ if (plat->base == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->base = (struct stm32_usart *)addr;
-
return 0;
}
-#endif
static const struct dm_serial_ops stm32_serial_ops = {
.putc = stm32_serial_putc,
diff --git a/drivers/serial/serial_stm32x7.h b/drivers/serial/serial_stm32x7.h
index 9fe37af5cc..b914edf28a 100644
--- a/drivers/serial/serial_stm32x7.h
+++ b/drivers/serial/serial_stm32x7.h
@@ -8,38 +8,65 @@
#ifndef _SERIAL_STM32_X7_
#define _SERIAL_STM32_X7_
-struct stm32_usart {
- u32 cr1;
- u32 cr2;
- u32 cr3;
- u32 brr;
- u32 gtpr;
- u32 rtor;
- u32 rqr;
- u32 sr;
- u32 icr;
- u32 rd_dr;
- u32 tx_dr;
+#define CR1_OFFSET(x) (x ? 0x0c : 0x00)
+#define CR3_OFFSET(x) (x ? 0x14 : 0x08)
+#define BRR_OFFSET(x) (x ? 0x08 : 0x0c)
+#define ISR_OFFSET(x) (x ? 0x00 : 0x1c)
+/*
+ * STM32F4 has one Data Register (DR) for received or transmitted
+ * data, so map Receive Data Register (RDR) and Transmit Data
+ * Register (TDR) at the same offset
+ */
+#define RDR_OFFSET(x) (x ? 0x04 : 0x24)
+#define TDR_OFFSET(x) (x ? 0x04 : 0x28)
+
+struct stm32_uart_info {
+ u8 uart_enable_bit; /* UART_CR1_UE */
+ bool stm32f4; /* true for STM32F4, false otherwise */
+ bool has_overrun_disable;
+ bool has_fifo;
+};
+
+struct stm32_uart_info stm32f4_info = {
+ .stm32f4 = true,
+ .uart_enable_bit = 13,
+ .has_overrun_disable = false,
+ .has_fifo = false,
+};
+
+struct stm32_uart_info stm32f7_info = {
+ .uart_enable_bit = 0,
+ .stm32f4 = false,
+ .has_overrun_disable = true,
+ .has_fifo = false,
+};
+
+struct stm32_uart_info stm32h7_info = {
+ .uart_enable_bit = 0,
+ .stm32f4 = false,
+ .has_overrun_disable = true,
+ .has_fifo = true,
};
/* Information about a serial port */
struct stm32x7_serial_platdata {
- struct stm32_usart *base; /* address of registers in physical memory */
+ fdt_addr_t base; /* address of registers in physical memory */
+ struct stm32_uart_info *uart_info;
unsigned long int clock_rate;
};
-#define USART_CR1_OVER8 (1 << 15)
-#define USART_CR1_TE (1 << 3)
-#define USART_CR1_RE (1 << 2)
-#define USART_CR1_UE (1 << 0)
+#define USART_CR1_FIFOEN BIT(29)
+#define USART_CR1_OVER8 BIT(15)
+#define USART_CR1_TE BIT(3)
+#define USART_CR1_RE BIT(2)
-#define USART_CR3_OVRDIS (1 << 12)
+#define USART_CR3_OVRDIS BIT(12)
-#define USART_SR_FLAG_RXNE (1 << 5)
-#define USART_SR_FLAG_TXE (1 << 7)
+#define USART_SR_FLAG_RXNE BIT(5)
+#define USART_SR_FLAG_TXE BIT(7)
-#define USART_BRR_F_MASK 0xFF
+#define USART_BRR_F_MASK GENMASK(7, 0)
#define USART_BRR_M_SHIFT 4
-#define USART_BRR_M_MASK 0xFFF0
+#define USART_BRR_M_MASK GENMASK(15, 4)
#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7ba7b580db..e6b7f11dc9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -65,6 +65,14 @@ config VIDEO_BPP32
this option, such displays will not be supported and console output
will be empty.
+config VIDEO_ANSI
+ bool "Support ANSI escape sequences in video console"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Enable ANSI escape sequence decoding for a more fully functional
+ console.
+
config CONSOLE_NORMAL
bool "Support a simple text console"
depends on DM_VIDEO
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index b5afd72227..5f63c12d6c 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -9,6 +9,7 @@
*/
#include <common.h>
+#include <linux/ctype.h>
#include <dm.h>
#include <video.h>
#include <video_console.h>
@@ -107,12 +108,213 @@ static void vidconsole_newline(struct udevice *dev)
video_sync(dev->parent);
}
+static const struct {
+ unsigned r;
+ unsigned g;
+ unsigned b;
+} colors[] = {
+ { 0x00, 0x00, 0x00 }, /* black */
+ { 0xff, 0x00, 0x00 }, /* red */
+ { 0x00, 0xff, 0x00 }, /* green */
+ { 0xff, 0xff, 0x00 }, /* yellow */
+ { 0x00, 0x00, 0xff }, /* blue */
+ { 0xff, 0x00, 0xff }, /* magenta */
+ { 0x00, 0xff, 0xff }, /* cyan */
+ { 0xff, 0xff, 0xff }, /* white */
+};
+
+static void set_color(struct video_priv *priv, unsigned idx, unsigned *c)
+{
+ switch (priv->bpix) {
+ case VIDEO_BPP16:
+ *c = ((colors[idx].r >> 3) << 0) |
+ ((colors[idx].g >> 2) << 5) |
+ ((colors[idx].b >> 3) << 11);
+ break;
+ case VIDEO_BPP32:
+ *c = 0xff000000 |
+ (colors[idx].r << 0) |
+ (colors[idx].g << 8) |
+ (colors[idx].b << 16);
+ break;
+ default:
+ /* unsupported, leave current color in place */
+ break;
+ }
+}
+
+static char *parsenum(char *s, int *num)
+{
+ char *end;
+ *num = simple_strtol(s, &end, 10);
+ return end;
+}
+
+/*
+ * Process a character while accumulating an escape string. Chars are
+ * accumulated into escape_buf until the end of escape sequence is
+ * found, at which point the sequence is parsed and processed.
+ */
+static void vidconsole_escape_char(struct udevice *dev, char ch)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+ if (!IS_ENABLED(CONFIG_VIDEO_ANSI))
+ goto error;
+
+ /* Sanity checking for bogus ESC sequences: */
+ if (priv->escape_len >= sizeof(priv->escape_buf))
+ goto error;
+ if (priv->escape_len == 0 && ch != '[')
+ goto error;
+
+ priv->escape_buf[priv->escape_len++] = ch;
+
+ /*
+ * Escape sequences are terminated by a letter, so keep
+ * accumulating until we get one:
+ */
+ if (!isalpha(ch))
+ return;
+
+ /*
+ * clear escape mode first, otherwise things will get highly
+ * surprising if you hit any debug prints that come back to
+ * this console.
+ */
+ priv->escape = 0;
+
+ switch (ch) {
+ case 'H':
+ case 'f': {
+ int row, col;
+ char *s = priv->escape_buf;
+
+ /*
+ * Set cursor position: [%d;%df or [%d;%dH
+ */
+ s++; /* [ */
+ s = parsenum(s, &row);
+ s++; /* ; */
+ s = parsenum(s, &col);
+
+ priv->ycur = row * priv->y_charsize;
+ priv->xcur_frac = priv->xstart_frac +
+ VID_TO_POS(col * priv->x_charsize);
+
+ break;
+ }
+ case 'J': {
+ int mode;
+
+ /*
+ * Clear part/all screen:
+ * [J or [0J - clear screen from cursor down
+ * [1J - clear screen from cursor up
+ * [2J - clear entire screen
+ *
+ * TODO we really only handle entire-screen case, others
+ * probably require some additions to video-uclass (and
+ * are not really needed yet by efi_console)
+ */
+ parsenum(priv->escape_buf + 1, &mode);
+
+ if (mode == 2) {
+ video_clear(dev->parent);
+ video_sync(dev->parent);
+ priv->ycur = 0;
+ priv->xcur_frac = priv->xstart_frac;
+ } else {
+ debug("unsupported clear mode: %d\n", mode);
+ }
+ break;
+ }
+ case 'm': {
+ struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+ char *s = priv->escape_buf;
+ char *end = &priv->escape_buf[priv->escape_len];
+
+ /*
+ * Set graphics mode: [%d;...;%dm
+ *
+ * Currently only supports the color attributes:
+ *
+ * Foreground Colors:
+ *
+ * 30 Black
+ * 31 Red
+ * 32 Green
+ * 33 Yellow
+ * 34 Blue
+ * 35 Magenta
+ * 36 Cyan
+ * 37 White
+ *
+ * Background Colors:
+ *
+ * 40 Black
+ * 41 Red
+ * 42 Green
+ * 43 Yellow
+ * 44 Blue
+ * 45 Magenta
+ * 46 Cyan
+ * 47 White
+ */
+
+ s++; /* [ */
+ while (s < end) {
+ int val;
+
+ s = parsenum(s, &val);
+ s++;
+
+ switch (val) {
+ case 30 ... 37:
+ /* fg color */
+ set_color(vid_priv, val - 30,
+ (unsigned *)&vid_priv->colour_fg);
+ break;
+ case 40 ... 47:
+ /* bg color */
+ set_color(vid_priv, val - 40,
+ (unsigned *)&vid_priv->colour_bg);
+ break;
+ default:
+ /* unknown/unsupported */
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ debug("unrecognized escape sequence: %*s\n",
+ priv->escape_len, priv->escape_buf);
+ }
+
+ return;
+
+error:
+ /* something went wrong, just revert to normal mode: */
+ priv->escape = 0;
+}
+
int vidconsole_put_char(struct udevice *dev, char ch)
{
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
int ret;
+ if (priv->escape) {
+ vidconsole_escape_char(dev, ch);
+ return 0;
+ }
+
switch (ch) {
+ case '\x1b':
+ priv->escape_len = 0;
+ priv->escape = 1;
+ break;
case '\a':
/* beep */
break;
@@ -163,6 +365,7 @@ static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
struct udevice *dev = sdev->priv;
vidconsole_put_char(dev, ch);
+ video_sync(dev->parent);
}
static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
@@ -260,6 +463,8 @@ static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
for (s = argv[1]; *s; s++)
vidconsole_put_char(dev, *s);
+ video_sync(dev->parent);
+
return 0;
}
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index dfa39b0d1b..dcaceed42c 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -87,7 +87,7 @@ int video_reserve(ulong *addrp)
return 0;
}
-static int video_clear(struct udevice *dev)
+void video_clear(struct udevice *dev)
{
struct video_priv *priv = dev_get_uclass_priv(dev);
@@ -100,8 +100,6 @@ static int video_clear(struct udevice *dev)
} else {
memset(priv->fb, priv->colour_bg, priv->fb_size);
}
-
- return 0;
}
/* Flush video activity to the caches */