mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] fs: fat: extend for in-PBL support
@ 2020-01-06 17:35 Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 1/5] pbl: add block I/O API Ahmad Fatoum
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Ahmad Fatoum @ 2020-01-06 17:35 UTC (permalink / raw)
  To: barebox; +Cc: lst

The AT91 BootROM loads a boot.bin file from the first FAT partition
into SRAM, when booting from MMC. SoCs like the Zynq do likewise.

To avoid the need for a different configuration for each of the bootloader
stages, add PBL support for reading from FAT.
This way each stage need only have a different PBL entry point.

The first two commits are valid as-is. The rest makes use of them for
the sama5d2. The sama5d2 first stage support is not yet complete (and
won't be for a while if it's up to me), but Lucas asked about it for
the Zynq, so here it is.

Feedback welcome.

Cheers,
Ahmad Fatoum (5):
  pbl: add block I/O API
  fs: fat: extend for in-PBL support
  mci: add first-stage at91-sdhci driver
  ARM: at91: add helpers for MCI barebox chain-loading
  [WIP] ARM: at91: sama5d27-som1: add first stage entry point

 arch/arm/boards/sama5d27-som1/lowlevel.c |  16 +
 arch/arm/mach-at91/Kconfig               |   6 +
 arch/arm/mach-at91/Makefile              |   1 +
 arch/arm/mach-at91/include/mach/xload.h  |  12 +
 arch/arm/mach-at91/xload-mmc.c           |  51 +++
 drivers/mci/Kconfig                      |   4 +
 drivers/mci/Makefile                     |   1 +
 drivers/mci/atmel-sdhci-common.c         | 279 ++++++++++++++
 drivers/mci/atmel-sdhci-pbl.c            | 440 +++++++++++++++++++++++
 drivers/mci/atmel-sdhci.h                |  38 ++
 drivers/mci/sdhci.h                      |  17 +
 fs/Makefile                              |   2 +-
 fs/fat/Kconfig                           |   7 +
 fs/fat/Makefile                          |   4 +-
 fs/fat/diskio.h                          |   7 +-
 fs/fat/fat-pbl.c                         | 148 ++++++++
 fs/fat/ff.c                              | 104 +++---
 fs/fat/ff.h                              |  17 +-
 images/Makefile.at91                     |   4 +
 include/pbl.h                            |   7 +
 20 files changed, 1112 insertions(+), 53 deletions(-)
 create mode 100644 arch/arm/mach-at91/include/mach/xload.h
 create mode 100644 arch/arm/mach-at91/xload-mmc.c
 create mode 100644 drivers/mci/atmel-sdhci-common.c
 create mode 100644 drivers/mci/atmel-sdhci-pbl.c
 create mode 100644 drivers/mci/atmel-sdhci.h
 create mode 100644 fs/fat/fat-pbl.c

-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC PATCH 1/5] pbl: add block I/O API
  2020-01-06 17:35 [RFC PATCH 0/5] fs: fat: extend for in-PBL support Ahmad Fatoum
@ 2020-01-06 17:35 ` Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 2/5] fs: fat: extend for in-PBL support Ahmad Fatoum
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Ahmad Fatoum @ 2020-01-06 17:35 UTC (permalink / raw)
  To: barebox; +Cc: lst

We already have some PBL MCI implementations in barebox, but none
are used for chainloading a barebox from a file system.

In preparation for supporting first stage boot on SoCs where it's
customary for both the BootROM and first stage bootloader to load the
follow-up stage from FAT, add a very basic block I/O API that MCI
drivers can implement.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 include/pbl.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/pbl.h b/include/pbl.h
index 787bd8293ff1..7cc162dfd039 100644
--- a/include/pbl.h
+++ b/include/pbl.h
@@ -7,6 +7,8 @@
 #ifndef __PBL_H__
 #define __PBL_H__
 
+#include <linux/types.h>
+
 extern unsigned long free_mem_ptr;
 extern unsigned long free_mem_end_ptr;
 
@@ -14,6 +16,10 @@ void pbl_barebox_uncompress(void *dest, void *compressed_start, unsigned int len
 
 #ifdef __PBL__
 #define IN_PBL	1
+struct pbl_bio {
+	void *priv;
+	int (*read)(struct pbl_bio *bio, off_t block_off, void *buf, unsigned int nblocks);
+};
 #else
 #define IN_PBL	0
 #endif
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC PATCH 2/5] fs: fat: extend for in-PBL support
  2020-01-06 17:35 [RFC PATCH 0/5] fs: fat: extend for in-PBL support Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 1/5] pbl: add block I/O API Ahmad Fatoum
@ 2020-01-06 17:35 ` Ahmad Fatoum
  2020-01-08 11:14   ` Sascha Hauer
  2020-01-06 17:35 ` [RFC PATCH 3/5] mci: add first-stage at91-sdhci driver Ahmad Fatoum
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Ahmad Fatoum @ 2020-01-06 17:35 UTC (permalink / raw)
  To: barebox; +Cc: lst

The AT91 BootROM loads a boot.bin file from the first FAT partition
into SRAM, when booting from MMC. To avoid the need for two barebox
configurations for each of the bootloader stages, add PBL support
for reading from FAT. This way each stage need only have a different
PBL entry point.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 fs/Makefile      |   2 +-
 fs/fat/Kconfig   |   7 +++
 fs/fat/Makefile  |   4 +-
 fs/fat/diskio.h  |   7 ++-
 fs/fat/fat-pbl.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/ff.c      | 104 +++++++++++++++++++--------------
 fs/fat/ff.h      |  17 ++++--
 include/pbl.h    |   1 +
 8 files changed, 237 insertions(+), 53 deletions(-)
 create mode 100644 fs/fat/fat-pbl.c

diff --git a/fs/Makefile b/fs/Makefile
index 9889a6507c1b..89ccc8947dc0 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_FS_RAMFS)	+= ramfs.o
 obj-y			+= devfs-core.o
 obj-$(CONFIG_FS_LEGACY) += legacy.o
 obj-$(CONFIG_FS_DEVFS)	+= devfs.o
-obj-$(CONFIG_FS_FAT)	+= fat/
+obj-pbl-$(CONFIG_FS_FAT)	+= fat/
 obj-y	+= fs.o libfs.o
 obj-$(CONFIG_FS_UBIFS)	+= ubifs/
 obj-$(CONFIG_FS_TFTP)	+= tftp.o
diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig
index b1def851cfb8..bc3b4b69e870 100644
--- a/fs/fat/Kconfig
+++ b/fs/fat/Kconfig
@@ -8,9 +8,16 @@ if FS_FAT
 config FS_FAT_WRITE
 	bool
 	prompt "FAT write support"
+	help
+	  Enable support for writing in FAT partitions.
+	  Note: This doesn't apply to FAT usage in barebox PBL.
+
 
 config FS_FAT_LFN
 	bool
 	prompt "Support long filenames"
+	help
+	  Enable support for file names other than 8.3.
+	  Note: This doesn't apply to FAT usage in barebox PBL.
 
 endif
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
index efc89ec67db8..2a8a787d5438 100644
--- a/fs/fat/Makefile
+++ b/fs/fat/Makefile
@@ -1 +1,3 @@
-obj-y += ff.o fat.o
+obj-y += fat.o
+pbl-y += fat-pbl.o
+obj-pbl-y += ff.o
diff --git a/fs/fat/diskio.h b/fs/fat/diskio.h
index f0d29dc390d5..aee1ce2b0b3b 100644
--- a/fs/fat/diskio.h
+++ b/fs/fat/diskio.h
@@ -4,7 +4,12 @@
 
 #ifndef _DISKIO
 
-#define _READONLY	0	/* 1: Remove write functions */
+#ifdef __PBL__
+#define _READONLY	1	/* 1: Remove write functions */
+#else
+#define _READONLY	0
+#endif
+
 #define _USE_IOCTL	1	/* 1: Use disk_ioctl fucntion */
 
 #include "integer.h"
diff --git a/fs/fat/fat-pbl.c b/fs/fat/fat-pbl.c
new file mode 100644
index 000000000000..bd158bff8278
--- /dev/null
+++ b/fs/fat/fat-pbl.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fat.c - FAT filesystem barebox driver
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ */
+
+#define pr_fmt(fmt) "fat-pbl: " fmt
+
+#include <common.h>
+#include "integer.h"
+#include "ff.h"
+#include "diskio.h"
+#include "pbl.h"
+
+/* ---------------------------------------------------------------*/
+
+DRESULT disk_read(FATFS *fat, BYTE *buf, DWORD sector, BYTE count)
+{
+	struct pbl_bio *bio = fat->userdata;
+	int ret;
+
+	debug("%s: sector: %ld count: %d\n", __func__, sector, count);
+
+	ret = bio->read(bio, sector, buf, count);
+	if (ret != count)
+		return ret;
+
+	return 0;
+}
+
+DSTATUS disk_status(FATFS *fat)
+{
+	return 0;
+}
+
+DWORD get_fattime(void)
+{
+	return 0;
+}
+
+DRESULT disk_ioctl (FATFS *fat, BYTE command, void *buf)
+{
+	return 0;
+}
+
+WCHAR ff_convert(WCHAR src, UINT dir)
+{
+	if (src <= 0x80)
+		return src;
+	else
+		return '?';
+}
+
+WCHAR ff_wtoupper(WCHAR chr)
+{
+	if (chr > 0x80)
+		return '?';
+
+	if ('a' <= chr && chr <= 'z')
+		return  chr + 'A' - 'a';
+
+	return chr;
+}
+
+static int fat_loadimage(FATFS *fs, const char *filename, void *dest, unsigned int len)
+{
+	FIL	file = {};
+	UINT	nread;
+	int	ret;
+
+	ret = f_open(fs, &file, filename, FA_OPEN_EXISTING | FA_READ);
+	if (ret) {
+		pr_debug("f_open(%s) failed: %d\n", filename, ret);
+		return ret;
+	}
+
+	ret = f_read(&file, dest, len, &nread);
+	if (ret) {
+		pr_debug("f_read failed: %d\n", ret);
+		return ret;
+	}
+
+	if (f_size(&file) > len)
+		return -ENOSPC;
+
+	return 0;
+}
+
+int pbl_fat_load(struct pbl_bio *bio, const char *filename, void *dest, unsigned int len)
+{
+	FATFS	fs = {};
+	int	ret;
+
+	fs.userdata = bio;
+
+	/* mount fs */
+	ret = f_mount(&fs);
+	if (ret) {
+		pr_debug("f_mount(%s) failed: %d\n", filename, ret);
+		return ret;
+	}
+
+	pr_debug("Reading file %s to 0x%p\n", filename, dest);
+
+	return fat_loadimage(&fs, filename, dest, len);
+}
+
+#define BS_55AA                     510     /* Boot sector signature (2) */
+#define BS_FilSysType               54      /* File system type (1) */
+#define BS_FilSysType32             82      /* File system type (1) */
+#define MBR_Table           446     /* MBR: Partition table offset (2) */
+#define MBR_StartSector             8
+
+enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec)
+{
+	/*
+	 * bootsec can be used to return index of the first sector in the
+	 * first partition
+	 */
+	if (bootsec)
+		*bootsec = 0;
+
+	/*
+	 * Check record signature (always placed at offset 510 even if the
+	 * sector size is > 512)
+	 */
+	if (get_unaligned_le16(&sector[BS_55AA]) != 0xAA55)
+		return filetype_unknown;
+
+	/* Check "FAT" string */
+	if ((get_unaligned_le32(&sector[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
+		return filetype_fat;
+
+	if ((get_unaligned_le32(&sector[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+		return filetype_fat;
+
+	if (bootsec)
+		/*
+		 * This must be an MBR, so return the starting sector of the
+		 * first partition so we could check if there is a FAT boot
+		 * sector there
+		 */
+		*bootsec = get_unaligned_le16(&sector[MBR_Table + MBR_StartSector]);
+
+	return filetype_mbr;
+}
+
diff --git a/fs/fat/ff.c b/fs/fat/ff.c
index 4d30433e5f03..29e4c8adb614 100644
--- a/fs/fat/ff.c
+++ b/fs/fat/ff.c
@@ -92,10 +92,24 @@
 #include <string.h>
 #include <errno.h>
 #include <malloc.h>
-#include <linux/ctype.h>
 #include <filetype.h>
 #include "ff.h"			/* FatFs configurations and declarations */
 #include "diskio.h"		/* Declarations of low level disk I/O functions */
+#include <pbl.h>
+
+#ifndef __PBL__
+#include <linux/ctype.h>
+#else
+static inline int isupper(int ch)
+{
+	return 'A' <= ch && ch <= 'Z';
+}
+
+static inline int islower(int ch)
+{
+	return 'a' <= ch && ch <= 'z';
+}
+#endif
 
 #if _FATFS != 8237
 #error Wrong include file (ff.h).
@@ -214,7 +228,7 @@
 #define	DDE			0xE5	/* Deleted directory enrty mark in DIR_Name[0] */
 #define	NDDE			0x05	/* Replacement of a character collides with DDE */
 
-#ifndef CONFIG_FS_FAT_LFN
+#ifndef FS_FAT_LFN
 #define	DEF_NAMEBUF		BYTE sfn[12]
 #define INIT_BUF(dobj)		(dobj).fn = sfn
 #define	FREE_BUF()
@@ -250,7 +264,7 @@ int move_window (
 
 	wsect = fs->winsect;
 	if (wsect != sector) {	/* Changed current window */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 		if (fs->wflag) {	/* Write back dirty window if needed */
 			if (disk_write(fs, fs->win, wsect, 1) != RES_OK)
 				return -EIO;
@@ -277,7 +291,7 @@ int move_window (
 /*
  * Clean-up cached data
  */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 static
 int sync (	/* 0: successful, -EIO: failed */
 	FATFS *fs	/* File system object */
@@ -372,7 +386,7 @@ static DWORD get_fat (	/* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster
 /*
  * FAT access - Change value of a FAT entry
  */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 
 static int put_fat (
 	FATFS *fs,	/* File system object */
@@ -431,7 +445,7 @@ static int put_fat (
 
 	return res;
 }
-#endif /* CONFIG_FS_FAT_WRITE */
+#endif /* FS_FAT_WRITE */
 
 
 
@@ -439,7 +453,7 @@ static int put_fat (
 /*
  * FAT handling - Remove a cluster chain
  */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 static
 int remove_chain (
 	FATFS *fs,			/* File system object */
@@ -506,7 +520,7 @@ int remove_chain (
 /*
  * FAT handling - Stretch or Create a cluster chain
  */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 static
 DWORD create_chain (	/* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
 	FATFS *fs,	/* File system object */
@@ -566,7 +580,7 @@ DWORD create_chain (	/* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err
 
 	return ncl; /* Return new cluster number or error code */
 }
-#endif /* CONFIG_FS_FAT_WRITE */
+#endif /* FS_FAT_WRITE */
 
 /*
  * Directory handling - Set directory index
@@ -657,7 +671,7 @@ static int dir_next (	/* 0:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and
 					return -EIO;
 
 				if (clst >= dj->fs->n_fatent) {	/* When it reached end of dynamic table */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 					BYTE c;
 
 					if (!stretch)
@@ -708,7 +722,7 @@ static int dir_next (	/* 0:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and
 /*
  * LFN handling - Test/Pick/Fit an LFN segment from/to directory entry
  */
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 
 /* Offset of LFN chars in the directory entry */
 static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};
@@ -784,7 +798,7 @@ int pick_lfn (		/* 1:Succeeded, 0:Buffer overflow */
 }
 
 
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 static
 void fit_lfn (
 	const WCHAR *lfnbuf,	/* Pointer to the LFN buffer */
@@ -824,7 +838,7 @@ void fit_lfn (
 /*
  * Create numbered name
  */
-#if defined(CONFIG_FS_FAT_LFN) && defined(CONFIG_FS_FAT_WRITE)
+#if defined(FS_FAT_LFN) && defined(FS_FAT_WRITE)
 static void gen_numname (
 	BYTE *dst,		/* Pointer to generated SFN */
 	const BYTE *src,	/* Pointer to source SFN to be modified */
@@ -874,7 +888,7 @@ static void gen_numname (
 /*
  * Calculate sum of an SFN
  */
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 static BYTE sum_sfn (
 	const BYTE *dir		/* Ptr to directory entry */
 )
@@ -897,7 +911,7 @@ static int dir_find (
 {
 	int res;
 	BYTE c, *dir;
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 	BYTE a, ord, sum;
 #endif
 
@@ -905,7 +919,7 @@ static int dir_find (
 	if (res != 0)
 		return res;
 
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 	ord = sum = 0xFF;
 #endif
 	do {
@@ -919,7 +933,7 @@ static int dir_find (
 			res = -ENOENT;
 			break;
 		}
-#ifdef CONFIG_FS_FAT_LFN	/* LFN configuration */
+#ifdef FS_FAT_LFN	/* LFN configuration */
 		a = dir[DIR_Attr] & AM_MASK;
 		if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) {
 			/* An entry without valid data */
@@ -970,7 +984,7 @@ static int dir_read (
 {
 	int res;
 	BYTE c, *dir;
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 	BYTE a, ord = 0xFF, sum = 0xFF;
 #endif
 
@@ -986,7 +1000,7 @@ static int dir_read (
 			res = -ENOENT;
 			break;
 		}
-#ifdef CONFIG_FS_FAT_LFN	/* LFN configuration */
+#ifdef FS_FAT_LFN	/* LFN configuration */
 		a = dir[DIR_Attr] & AM_MASK;
 		if (c == DDE || c == '.' || ((a & AM_VOL) && a != AM_LFN)) {	/* An entry without valid data */
 			ord = 0xFF;
@@ -1025,7 +1039,7 @@ static int dir_read (
 /*
  * Register an object to the directory
  */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 static
 int dir_register (	/* 0:Successful, FR_DENIED:No free entry or too many SFN collision, -EIO:Disk error */
 	FF_DIR *dj	/* Target directory with object name to be created */
@@ -1033,7 +1047,7 @@ int dir_register (	/* 0:Successful, FR_DENIED:No free entry or too many SFN coll
 {
 	int res;
 	BYTE c, *dir;
-#ifdef CONFIG_FS_FAT_LFN	/* LFN configuration */
+#ifdef FS_FAT_LFN	/* LFN configuration */
 	WORD n, ne, is;
 	BYTE sn[12], *fn, sum;
 	WCHAR *lfn;
@@ -1127,7 +1141,7 @@ int dir_register (	/* 0:Successful, FR_DENIED:No free entry or too many SFN coll
 			dir = dj->dir;
 			memset(dir, 0, SZ_DIR);	/* Clean the entry */
 			memcpy(dir, dj->fn, 11);	/* Put SFN */
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 			dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);	/* Put NT flag */
 #endif
 			dj->fs->wflag = 1;
@@ -1136,18 +1150,18 @@ int dir_register (	/* 0:Successful, FR_DENIED:No free entry or too many SFN coll
 
 	return res;
 }
-#endif /* CONFIG_FS_FAT_WRITE */
+#endif /* FS_FAT_WRITE */
 
 /*
  * Remove an object from the directory
  */
-#if defined CONFIG_FS_FAT_WRITE
+#if defined FS_FAT_WRITE
 static int dir_remove (	/* 0: Successful, -EIO: A disk error */
 	FF_DIR *dj				/* Directory object pointing the entry to be removed */
 )
 {
 	int res;
-#ifdef CONFIG_FS_FAT_LFN	/* LFN configuration */
+#ifdef FS_FAT_LFN	/* LFN configuration */
 	WORD i;
 
 	i = dj->index;	/* SFN index */
@@ -1181,7 +1195,7 @@ static int dir_remove (	/* 0: Successful, -EIO: A disk error */
 
 	return res;
 }
-#endif /* CONFIG_FS_FAT_WRITE */
+#endif /* FS_FAT_WRITE */
 
 /*
  * Pick a segment and create the object name in directory form
@@ -1195,7 +1209,7 @@ static int create_name (
 	static const BYTE excvt[] = _EXCVT;	/* Upper conversion table for extended chars */
 #endif
 
-#ifdef CONFIG_FS_FAT_LFN	/* LFN configuration */
+#ifdef FS_FAT_LFN	/* LFN configuration */
 	BYTE b, cf;
 	WCHAR w, *lfn;
 	UINT i, ni, si, di;
@@ -1410,7 +1424,7 @@ static void get_fileinfo (		/* No return code */
 				break;
 			if (c == NDDE)
 				c = (TCHAR)DDE;
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 			if ((nt & NS_BODY) && isupper(c))
 				c += 0x20;
 #endif
@@ -1428,7 +1442,7 @@ static void get_fileinfo (		/* No return code */
 				c = dir[i];
 				if (c == ' ')
 					break;
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 				if ((nt & NS_EXT) && isupper(c))
 					c += 0x20;
 #endif
@@ -1449,7 +1463,7 @@ static void get_fileinfo (		/* No return code */
 	}
 	*p = 0;		/* Terminate SFN str by a \0 */
 
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 	if (fno->lfname && fno->lfsize) {
 		TCHAR *tp = fno->lfname;
 		WCHAR w, *lfn;
@@ -1668,7 +1682,7 @@ static int chk_mounted (	/* 0(0): successful, !=0: any error occurred */
 	if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
 		return -EINVAL;
 
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 	/* Initialize cluster allocation information */
 	fs->free_clust = 0xFFFFFFFF;
 	fs->last_clust = 0;
@@ -1723,7 +1737,7 @@ int f_open (
 
 	fp->fs = NULL;		/* Clear file object */
 
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 	mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
 	dj.fs = fatfs;
 #else
@@ -1735,7 +1749,7 @@ int f_open (
 		res = follow_path(&dj, path);	/* Follow the file path */
 	dir = dj.dir;
 
-#ifdef CONFIG_FS_FAT_WRITE	/* R/W configuration */
+#ifdef FS_FAT_WRITE	/* R/W configuration */
 	if (res == 0) {
 		if (!dir)	/* Current dir itself */
 			res = -EISDIR;
@@ -1870,7 +1884,7 @@ int f_read (
 					cc = fp->fs->csize - csect;
 				if (disk_read(fp->fs, rbuff, sect, (BYTE)cc) != RES_OK)
 					ABORT(fp->fs, -EIO);
-#if defined CONFIG_FS_FAT_WRITE
+#if defined FS_FAT_WRITE
 				/* Replace one of the read sectors with cached data if it contains a dirty sector */
 				if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
 					memcpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
@@ -1879,7 +1893,7 @@ int f_read (
 				continue;
 			}
 			if (fp->dsect != sect) {	/* Load data sector if not in cache */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 				if (fp->flag & FA__DIRTY) {	/* Write-back dirty sector cache */
 					if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK)
 						ABORT(fp->fs, -EIO);
@@ -1903,7 +1917,7 @@ int f_read (
 
 
 
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 /*
  * Write File
  */
@@ -2044,7 +2058,7 @@ int f_sync (
 	return res;
 }
 
-#endif /* CONFIG_FS_FAT_WRITE */
+#endif /* FS_FAT_WRITE */
 
 /*
  * Close File
@@ -2053,7 +2067,7 @@ int f_close (
 	FIL *fp		/* Pointer to the file object to be closed */
 )
 {
-#ifndef CONFIG_FS_FAT_WRITE
+#ifndef FS_FAT_WRITE
 	fp->fs = 0;	/* Discard file object */
 	return 0;
 #else
@@ -2082,7 +2096,7 @@ int f_lseek (
 		return -ERESTARTSYS;
 
 	if (ofs > fp->fsize	/* In read-only mode, clip offset with the file size */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 		 && !(fp->flag & FA_WRITE)
 #endif
 		) ofs = fp->fsize;
@@ -2098,7 +2112,7 @@ int f_lseek (
 			clst = fp->clust;
 		} else {					/* When seek to back cluster, */
 			clst = fp->sclust;			/* start from the first cluster */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 			if (clst == 0) {			/* If no cluster chain, create a new chain */
 				clst = create_chain(fp->fs, 0);
 				if (clst == 1)
@@ -2112,7 +2126,7 @@ int f_lseek (
 		}
 		if (clst != 0) {
 			while (ofs > bcs) {	/* Cluster following loop */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 				if (fp->flag & FA_WRITE) {	/* Check if in write mode or not */
 					/* Force stretch if in write mode */
 					clst = create_chain(fp->fs, clst);
@@ -2143,7 +2157,7 @@ int f_lseek (
 		}
 	}
 	if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {	/* Fill sector cache if needed */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 		if (fp->flag & FA__DIRTY) {	/* Write-back dirty sector cache */
 			if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK)
 				ABORT(fp->fs, -EIO);
@@ -2154,7 +2168,7 @@ int f_lseek (
 			ABORT(fp->fs, -EIO);
 		fp->dsect = nsect;
 	}
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 	if (fp->fptr > fp->fsize) {	/* Set file change flag if the file size is extended */
 		fp->fsize = fp->fptr;
 		fp->flag |= FA__WRITTEN;
@@ -2269,7 +2283,7 @@ int f_stat (
 	return res;
 }
 
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 /*
  * Get Number of Free Clusters
  */
@@ -2706,4 +2720,4 @@ out:
 
 	return res;
 }
-#endif /* CONFIG_FS_FAT_WRITE */
+#endif /* FS_FAT_WRITE */
diff --git a/fs/fat/ff.h b/fs/fat/ff.h
index e86ca3aae063..57a86805c93a 100644
--- a/fs/fat/ff.h
+++ b/fs/fat/ff.h
@@ -17,6 +17,13 @@
 #ifndef _FATFS
 #define _FATFS	8237	/* Revision ID */
 
+#if defined(CONFIG_FS_FAT_LFN) && !defined(__PBL__)
+#define FS_FAT_LFN 1
+#endif
+#if defined(CONFIG_FS_FAT_WRITE) && !defined(__PBL__)
+#define FS_FAT_WRITE 1
+#endif
+
 #include <asm/unaligned.h>
 #include <linux/list.h>
 
@@ -30,7 +37,7 @@
 /* Type of path name strings on FatFs API */
 
 #if _LFN_UNICODE			/* Unicode string */
-#ifndef CONFIG_FS_FAT_LFN
+#ifndef FS_FAT_LFN
 #error _LFN_UNICODE must be 0 in non-LFN cfg.
 #endif
 #ifndef _INC_TCHAR
@@ -63,7 +70,7 @@ typedef struct {
 #if _MAX_SS != 512
 	WORD	ssize;		/* Bytes per sector (512,1024,2048,4096) */
 #endif
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 	DWORD	last_clust;	/* Last allocated cluster */
 	DWORD	free_clust;	/* Number of free clusters */
 	DWORD	fsi_sector;	/* fsinfo sector (FAT32) */
@@ -92,7 +99,7 @@ typedef struct {
 	DWORD	sclust;		/* File start cluster (0 when fsize==0) */
 	DWORD	clust;		/* Current cluster */
 	DWORD	dsect;		/* Current data sector */
-#ifdef CONFIG_FS_FAT_WRITE
+#ifdef FS_FAT_WRITE
 	DWORD	dir_sect;	/* Sector containing the directory entry */
 	BYTE*	dir_ptr;	/* Ponter to the directory entry in the window */
 #endif
@@ -119,7 +126,7 @@ typedef struct {
 	DWORD	sect;			/* Current sector */
 	BYTE*	dir;			/* Pointer to the current SFN entry in the win[] */
 	BYTE*	fn;			/* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 	WCHAR*	lfn;			/* Pointer to the LFN working buffer */
 	WORD	lfn_idx;		/* Last matched LFN index number (0xFFFF:No LFN) */
 #endif
@@ -135,7 +142,7 @@ typedef struct {
 	WORD	ftime;			/* Last modified time */
 	BYTE	fattrib;		/* Attribute */
 	TCHAR	fname[13];		/* Short file name (8.3 format) */
-#ifdef CONFIG_FS_FAT_LFN
+#ifdef FS_FAT_LFN
 	TCHAR*	lfname;			/* Pointer to the LFN buffer */
 	UINT 	lfsize;			/* Size of LFN buffer in TCHAR */
 #endif
diff --git a/include/pbl.h b/include/pbl.h
index 7cc162dfd039..346bdc006f39 100644
--- a/include/pbl.h
+++ b/include/pbl.h
@@ -20,6 +20,7 @@ struct pbl_bio {
 	void *priv;
 	int (*read)(struct pbl_bio *bio, off_t block_off, void *buf, unsigned int nblocks);
 };
+int pbl_fat_load(struct pbl_bio *, const char *filename, void *dest, unsigned int len);
 #else
 #define IN_PBL	0
 #endif
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC PATCH 3/5] mci: add first-stage at91-sdhci driver
  2020-01-06 17:35 [RFC PATCH 0/5] fs: fat: extend for in-PBL support Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 1/5] pbl: add block I/O API Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 2/5] fs: fat: extend for in-PBL support Ahmad Fatoum
@ 2020-01-06 17:35 ` Ahmad Fatoum
  2020-01-08 11:23   ` Sascha Hauer
  2020-01-06 17:35 ` [RFC PATCH 4/5] ARM: at91: add helpers for MCI barebox chain-loading Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 5/5] [WIP] ARM: at91: sama5d27-som1: add first stage entry point Ahmad Fatoum
  4 siblings, 1 reply; 8+ messages in thread
From: Ahmad Fatoum @ 2020-01-06 17:35 UTC (permalink / raw)
  To: barebox; +Cc: lst

This commit imports the at91bootstrap v3.9.1-rc1 state of the
Atmel SDHCI variant driver.

Second stage use is not implemented and first stage use in general is
not possible, because SDRAM set up is not yet implemented.
However, it can already be used to show case the use of FAT from the
barebox PBL used in a follow up commit.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 drivers/mci/Kconfig              |   4 +
 drivers/mci/Makefile             |   1 +
 drivers/mci/atmel-sdhci-common.c | 279 ++++++++++++++++++++
 drivers/mci/atmel-sdhci-pbl.c    | 440 +++++++++++++++++++++++++++++++
 drivers/mci/atmel-sdhci.h        |  38 +++
 drivers/mci/sdhci.h              |  17 ++
 6 files changed, 779 insertions(+)
 create mode 100644 drivers/mci/atmel-sdhci-common.c
 create mode 100644 drivers/mci/atmel-sdhci-pbl.c
 create mode 100644 drivers/mci/atmel-sdhci.h

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 80b3a26002b4..7485be5dcb6e 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -177,3 +177,7 @@ endif
 config MCI_IMX_ESDHC_PBL
 	bool
 	select MCI_SDHCI
+
+config MCI_ATMEL_SDHCI_PBL
+	bool
+	select MCI_SDHCI
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 54eb65978e5d..40ed772d3ff7 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_MCI_ATMEL)		+= atmel_mci.o
 obj-$(CONFIG_MCI_BCM283X)	+= mci-bcm2835.o
 obj-$(CONFIG_MCI_BCM283X_SDHOST)	+= bcm2835-sdhost.o
 obj-$(CONFIG_MCI_DOVE)		+= dove-sdhci.o
+pbl-$(CONFIG_MCI_ATMEL_SDHCI_PBL)	+= atmel-sdhci-pbl.o atmel-sdhci-common.o
 obj-$(CONFIG_MCI_IMX)		+= imx.o
 obj-$(CONFIG_MCI_IMX_ESDHC)	+= imx-esdhc.o imx-esdhc-common.o
 pbl-$(CONFIG_MCI_IMX_ESDHC_PBL)	+= imx-esdhc-pbl.o imx-esdhc-common.o
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
new file mode 100644
index 000000000000..499627e2e396
--- /dev/null
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: BSD-1-Clause
+/*
+ * Copyright (c) 2015, Atmel Corporation
+ * Copyright (c) 2019, Ahmad Fatoum, Pengutronix
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ */
+
+#define pr_fmt(fmt) "atmel-sdhci: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <mci.h>
+#include <debug_ll.h>
+#include "atmel-sdhci.h"
+
+#define SDHCI_CARD_INSERTED		BIT(16)
+
+static u32 at91_sdhci_read32(struct sdhci *sdhci, int reg)
+{
+	struct at91_sdhci *priv = container_of(sdhci, struct at91_sdhci, sdhci);
+	return readl(priv->base + reg);
+}
+
+static void at91_sdhci_write32(struct sdhci *sdhci, int reg, u32 value)
+{
+	struct at91_sdhci *priv = container_of(sdhci, struct at91_sdhci, sdhci);
+	writel(value, priv->base + reg);
+}
+
+static u16 at91_sdhci_read16(struct sdhci *sdhci, int reg)
+{
+	struct at91_sdhci *priv = container_of(sdhci, struct at91_sdhci, sdhci);
+	return readw(priv->base + reg);
+}
+
+static void at91_sdhci_write16(struct sdhci *sdhci, int reg, u16 value)
+{
+	struct at91_sdhci *priv = container_of(sdhci, struct at91_sdhci, sdhci);
+	writew(value, priv->base + reg);
+}
+
+static u8 at91_sdhci_read8(struct sdhci *sdhci, int reg)
+{
+	struct at91_sdhci *priv = container_of(sdhci, struct at91_sdhci, sdhci);
+	return readb(priv->base + reg);
+}
+
+static void at91_sdhci_write8(struct sdhci *sdhci, int reg, u8 value)
+{
+	struct at91_sdhci *priv = container_of(sdhci, struct at91_sdhci, sdhci);
+	writeb(value, priv->base + reg);
+}
+
+static void at91_sdhci_software_reset_cmd(struct at91_sdhci *host)
+{
+	sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, SDHCI_RESET_CMD);
+
+	while (sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_CMD)
+		;
+}
+
+void at91_sdhci_host_capability(struct at91_sdhci *host,
+				unsigned int *voltages)
+{
+	u16 caps;
+
+	caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+
+	if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
+		*voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+	if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
+		*voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+	if (caps & SDHCI_HOSTCAP_VOLTAGE_180)
+		*voltages |= MMC_VDD_165_195;
+}
+
+bool at91_sdhci_is_card_inserted(struct at91_sdhci *host)
+{
+	/*
+	 * Debouncing of the card detect pin is up to 13ms on sama5d2 rev B
+	 * and later.
+	 * Try to be safe and wait for up to 50ms (50000µs). Let assume
+	 * the PCK (processor clock) frequency is 500MHz, hence 500 cycles/µs.
+	 * 500 * 50000 = 25000000 cycles.
+	 */
+	unsigned int timeout = 25000000;
+	bool is_inserted;
+	u32 status_mask;
+
+	/* Enable (unmask) the Interrupt Status 'card inserted' bit */
+	status_mask = sdhci_read32(&host->sdhci, SDHCI_INT_ENABLE);
+	status_mask |= SDHCI_INT_CARD_INSERT;
+	sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, status_mask);
+
+	is_inserted = !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_INSERTED);
+	if (is_inserted)
+		goto exit;
+
+	while (!(sdhci_read32(&host->sdhci, SDHCI_INT_STATUS) & SDHCI_INT_CARD_INSERT)
+	       && timeout--)
+		;
+
+	is_inserted = !!(sdhci_read32(&host->sdhci, SDHCI_INT_STATUS) &
+			 SDHCI_INT_CARD_INSERT);
+
+exit:
+	status_mask &= ~SDHCI_INT_CARD_INSERT;
+	sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, status_mask);
+
+	status_mask = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+	status_mask |= SDHCI_INT_CARD_INSERT;
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, status_mask);
+
+	return is_inserted;
+}
+
+static void at91_sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
+				   struct mci_data *data, bool dma, u32 *command,
+				   u32 *xfer)
+{
+	*xfer = 0;
+
+	*command = SDHCI_CMD_INDEX(cmd->cmdidx);
+
+	if ((cmd->resp_type == SD_RESP_TYPE_R1)
+		|| (cmd->resp_type == SD_RESP_TYPE_R5)
+		|| (cmd->resp_type == SD_RESP_TYPE_R6)
+		|| (cmd->resp_type == SD_RESP_TYPE_R7))
+		*command |= SDHCI_RESP_TYPE_48
+			| SDHCI_CMD_CRC_CHECK_EN
+			| SDHCI_CMD_INDEX_CHECK_EN;
+	else if (cmd->resp_type == SD_RESP_TYPE_R1B)
+		*command |= SDHCI_RESP_TYPE_48_BUSY
+			| SDHCI_CMD_CRC_CHECK_EN
+			| SDHCI_CMD_INDEX_CHECK_EN;
+	else if (cmd->resp_type == SD_RESP_TYPE_R2)
+		*command |= SDHCI_RESP_TYPE_136
+			| SDHCI_CMD_CRC_CHECK_EN;
+	else if ((cmd->resp_type == SD_RESP_TYPE_R3)
+		|| (cmd->resp_type == SD_RESP_TYPE_R4))
+		*command |= SDHCI_RESP_TYPE_48;
+	else
+		*command |= SDHCI_RESP_NONE;
+
+	if (data) {
+		*command |= SDHCI_DATA_PRESENT;
+
+		*xfer |= SDHCI_BLOCK_COUNT_EN;
+
+		if (data->blocks > 1)
+			*xfer |= SDHCI_MULTIPLE_BLOCKS;
+
+		if (data->flags & MMC_DATA_READ)
+			*xfer |= SDHCI_DATA_TO_HOST;
+
+		if (dma)
+			*xfer |= SDHCI_DMA_EN;
+	}
+}
+
+int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *sd_cmd,
+			    struct mci_data *data)
+{
+	unsigned int normal_status, normal_status_mask;
+	unsigned int command, xfer;
+	unsigned int timeout;
+
+	timeout = 100000;
+	while ((--timeout) &&
+	       (sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) &
+		(SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA)))
+		;
+
+	if (!timeout)
+		pr_warn("SDHC: Timeout waiting for CMD and DAT Inhibit bits\n");
+
+	normal_status_mask = SDHCI_INT_CMD_COMPLETE;
+
+	at91_sdhci_set_cmd_xfer_mode(&host->sdhci, sd_cmd,
+			       data, false, &command,
+			       &xfer);
+
+	if (sd_cmd->resp_type == SD_RESP_TYPE_R1B)
+		normal_status_mask |= SDHCI_INT_XFER_COMPLETE;
+
+	if (data) {
+		sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
+		sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, data->blocksize);
+		if (data->blocks > 1)
+			sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+
+		sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+	}
+
+	sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, sd_cmd->cmdarg);
+
+	sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
+
+	timeout = 100000;
+	do {
+		normal_status = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
+	} while ((--timeout) &&
+		 ((normal_status & normal_status_mask) != normal_status_mask));
+
+	if (!timeout)
+		pr_debug("SDHC: Timeout waiting for command complete\n");
+
+	/* clear the status, except for read and write ready.
+	 * those will be cleared by the read/write data routine, which
+	 * bases itself on the fact that the hardware is ready to receive data
+	 * or has data ready to be read
+	 */
+	sdhci_write16(&host->sdhci, SDHCI_INT_NORMAL_STATUS,
+		    normal_status & ~(SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL));
+
+	if ((normal_status & normal_status_mask) == normal_status_mask) {
+		sdhci_read_response(&host->sdhci, sd_cmd);
+
+		/* if we have data but not using block transfer, we use PIO mode */
+		if (data)
+			sdhci_transfer_data(&host->sdhci, data);
+
+		return 0;
+	}
+
+	normal_status = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+
+	at91_sdhci_software_reset_cmd(host);
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, normal_status);
+
+	if (normal_status & SDHCI_INT_TIMEOUT)
+		return -ETIMEDOUT;
+
+	return -EIO;
+}
+
+#define DEFAULT_SD_BLOCK_LEN		512
+
+int atmel_sdhci_init(struct at91_sdhci *host)
+{
+	unsigned int status_mask;
+
+	status_mask = SDHCI_INT_CMD_COMPLETE
+		| SDHCI_INT_XFER_COMPLETE
+		| SDHCI_INT_SPACE_AVAIL
+		| SDHCI_INT_DATA_AVAIL;
+
+	status_mask |= SDHCI_INT_TIMEOUT
+		| SDHCI_INT_CRC
+		| SDHCI_INT_END_BIT
+		| SDHCI_INT_INDEX
+		| SDHCI_INT_DATA_TIMEOUT
+		| SDHCI_INT_DATA_CRC
+		| SDHCI_INT_DATA_END_BIT;
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, status_mask);
+
+	sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0);
+
+	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL,
+		     sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL)
+		     & ~(SDHCI_DATA_WIDTH_8BIT | SDHCI_DATA_WIDTH_4BIT));
+
+	return 0;
+}
+
+void atmel_sdhci_prep(struct at91_sdhci *host, void __iomem *base)
+{
+	host->base = base;
+	host->sdhci.read8 = at91_sdhci_read8;
+	host->sdhci.read16 = at91_sdhci_read16;
+	host->sdhci.read32 = at91_sdhci_read32;
+	host->sdhci.write8 = at91_sdhci_write8;
+	host->sdhci.write16 = at91_sdhci_write16;
+	host->sdhci.write32 = at91_sdhci_write32;
+}
diff --git a/drivers/mci/atmel-sdhci-pbl.c b/drivers/mci/atmel-sdhci-pbl.c
new file mode 100644
index 000000000000..52d15a7c0c76
--- /dev/null
+++ b/drivers/mci/atmel-sdhci-pbl.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: BSD-1-Clause
+/*
+ * Copyright (c) 2015, Atmel Corporation
+ * Copyright (c) 2019, Ahmad Fatoum, Pengutronix
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ */
+
+#include <common.h>
+#include <pbl.h>
+#include <mci.h>
+#include <debug_ll.h>
+#include <mach/xload.h>
+#include "atmel-sdhci.h"
+
+#define DEFAULT_SD_BLOCK_LEN		512
+#define SUPPORT_MAX_BLOCKS		16U
+
+#define OCR_VOLTAGE_27_36_MASK		0xff8000
+#define CHECK_PATTERN			0xaa
+
+struct at91_sdhci_priv {
+	struct at91_sdhci host;
+
+	unsigned int voltages;
+	u32 rca;	/* Relative card address */
+	u32 ocr;	/* Operation condition register */
+	bool no_sd;
+	bool highcapacity_card;
+};
+
+/*
+ * Use time in us as a busy counter timeout value
+ */
+static inline void early_udelay(unsigned us)
+{
+	volatile unsigned i;
+
+	for (i = 0; i < us * 4; i++)
+		;
+}
+
+static int sd_cmd_send_status(struct at91_sdhci_priv *priv, unsigned int retries)
+{
+	unsigned int i;
+	int ret;
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_SEND_STATUS,
+		.resp_type = SD_RESP_TYPE_R1,
+		.cmdarg = priv->rca << 16,
+	};
+
+	for (i = 0; i < retries; i++) {
+		ret = at91_sdhci_send_command(&priv->host, &cmd, NULL);
+		if (ret)
+			return ret;
+
+		if ((cmd.response[0] >> 8) & 0x01)
+			break;
+
+		early_udelay(1000);
+	};
+
+	if (i == retries) {
+		pr_warn("Timeout, wait for card ready\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int sd_cmd_stop_transmission(struct at91_sdhci_priv *priv)
+{
+	unsigned int retries = 1000;
+	int ret;
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_STOP_TRANSMISSION,
+		.resp_type = SD_RESP_TYPE_R1B,
+	};
+
+	ret = at91_sdhci_send_command(&priv->host, &cmd, NULL);
+	if (ret)
+		return ret;
+
+	return sd_cmd_send_status(priv, retries);
+}
+
+static int sd_cmd_read_multiple_block(struct at91_sdhci_priv *priv,
+				      void *buf,
+				      unsigned int start,
+				      unsigned int block_count)
+{
+	u16 block_len = DEFAULT_SD_BLOCK_LEN;
+	struct mci_data data;
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK,
+		.resp_type = SD_RESP_TYPE_R1,
+		.cmdarg = start,
+	};
+
+	if (!priv->highcapacity_card)
+		cmd.cmdarg *= block_len;
+
+	data.dest = buf;
+	data.flags = MMC_DATA_READ;
+	data.blocksize = block_len;
+	data.blocks = block_count;
+
+	return at91_sdhci_send_command(&priv->host, &cmd, &data);
+}
+
+
+static int atmel_sdhci_bio_read(struct pbl_bio *bio, off_t start,
+				void *buf, unsigned int nblocks)
+{
+	struct at91_sdhci_priv *priv = bio->priv;
+	unsigned int blocks_done = 0;
+	unsigned int blocks;
+	unsigned int block_len = DEFAULT_SD_BLOCK_LEN;
+	unsigned int blocks_read;
+	int ret;
+
+	/*
+	 * Refer to the at91sam9g20 datasheet:
+	 * Figure 35-10. Read Function Flow Diagram
+	*/
+
+	while (blocks_done < nblocks) {
+		blocks = min(nblocks - blocks_done, SUPPORT_MAX_BLOCKS);
+
+		blocks_read = sd_cmd_read_multiple_block(priv, buf,
+							 start + blocks_done,
+							 blocks);
+
+		ret = sd_cmd_stop_transmission(priv);
+		if (ret)
+			return ret;
+
+		blocks_done += blocks_read;
+
+		if (blocks_read != blocks)
+			break;
+
+		buf += blocks * block_len;
+	}
+
+	return blocks_done;
+}
+
+static int sd_cmd_go_idle_state(struct at91_sdhci_priv *priv)
+{
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_GO_IDLE_STATE,
+		.resp_type = MMC_RSP_NONE,
+	};
+
+	return at91_sdhci_send_command(&priv->host, &cmd, NULL);
+}
+
+static int sd_cmd_send_if_cond(struct at91_sdhci_priv *priv)
+{
+	int ret;
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_SEND_EXT_CSD,
+		.resp_type = SD_RESP_TYPE_R1,
+		.cmdarg = CHECK_PATTERN,
+	};
+
+	if (priv->voltages & OCR_VOLTAGE_27_36_MASK)
+		cmd.cmdarg |= 0x01 << 8;
+
+	ret = at91_sdhci_send_command(&priv->host, &cmd, NULL);
+	if (ret)
+		return ret;
+
+	if (((cmd.response[0] & CHECK_PATTERN) != CHECK_PATTERN)
+		|| (((cmd.response[0] >> 8) & 0x0f) != 0x01))
+		return -EIO;
+
+	return 0;
+}
+
+static int sd_cmd_send_app_cmd(struct at91_sdhci_priv *priv)
+{
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_APP_CMD,
+		.resp_type = SD_RESP_TYPE_R1,
+		.cmdarg = priv->rca << 16,
+	};
+
+	return at91_sdhci_send_command(&priv->host, &cmd, NULL);
+}
+
+static int sd_cmd_app_sd_send_op_cmd(struct at91_sdhci_priv *priv,
+				unsigned int capacity_support,
+				unsigned int *reponse)
+{
+	int ret;
+	struct mci_cmd cmd = {
+		.cmdidx = SD_CMD_APP_SEND_OP_COND,
+		.resp_type = SD_RESP_TYPE_R3,
+		.cmdarg = priv->voltages & OCR_VOLTAGE_27_36_MASK,
+	};
+
+	if (capacity_support)
+		cmd.cmdarg |= OCR_HCS;
+
+	ret = at91_sdhci_send_command(&priv->host, &cmd, NULL);
+	if (ret)
+		return ret;
+
+	*reponse = cmd.response[0];
+
+	return 0;
+}
+
+static int sd_check_operational_condition(struct at91_sdhci_priv *priv,
+			unsigned int capacity_support)
+{
+	unsigned int response = 0;
+	unsigned int retries = 1000;
+	unsigned int i;
+	int ret;
+
+	/*
+	 * The host repeatedly issues ACMD41 for at least 1 second
+	 * or until the busy bit are set to 1.
+	 */
+	for (i = 0; i < retries; i++) {
+		ret = sd_cmd_send_app_cmd(priv);
+		if (ret)
+			return ret;
+
+		ret = sd_cmd_app_sd_send_op_cmd(priv,
+				capacity_support, &response);
+		if (ret)
+			return ret;
+
+		if (response & OCR_BUSY)
+			break;
+
+		early_udelay(1000);
+	};
+
+	if (i == retries)
+		return -EIO;
+
+	priv->ocr = response;
+
+	return 0;
+}
+
+static int sd_cmd_all_send_cid(struct at91_sdhci_priv *priv)
+{
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_ALL_SEND_CID,
+		.resp_type = SD_RESP_TYPE_R2,
+	};
+
+	return at91_sdhci_send_command(&priv->host, &cmd, NULL);
+}
+
+static int sd_cmd_send_relative_addr(struct at91_sdhci_priv *priv)
+{
+	int ret;
+	struct mci_cmd cmd = {
+		.cmdidx = SD_CMD_SEND_RELATIVE_ADDR,
+		.resp_type = SD_RESP_TYPE_R6,
+	};
+
+	priv->rca = 1;
+	cmd.cmdarg = priv->rca << 16,
+
+	ret = at91_sdhci_send_command(&priv->host, &cmd, NULL);
+	if (ret)
+		return ret;
+
+	if (!priv->no_sd)
+		priv->rca = (cmd.response[0] >> 16) & 0xffff;
+
+	return 0;
+}
+
+static int sd_cmd_select_card(struct at91_sdhci_priv *priv)
+{
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_SELECT_CARD,
+		.resp_type = SD_RESP_TYPE_R1,
+		.cmdarg = priv->rca << 16,
+	};
+
+	return at91_sdhci_send_command(&priv->host, &cmd, NULL);
+}
+
+#define OCR_VOLTAGE_WIN_27_36	0x00FF8000
+#define OCR_ACCESS_MODE		0x60000000
+
+#define OCR_ACCESS_MODE_BYTE	(0x00 << 30)
+#define OCR_ACCESS_MODE_SECTOR	(0x01 << 30)
+
+static int mmc_cmd_send_op_cond(struct at91_sdhci_priv *priv,
+				unsigned int *ocr)
+{
+	struct mci_cmd cmd = {
+		.cmdidx = MMC_CMD_SEND_OP_COND,
+		.resp_type = SD_RESP_TYPE_R3,
+		.cmdarg = *ocr & (OCR_VOLTAGE_WIN_27_36 | OCR_ACCESS_MODE),
+	};
+	int ret;
+
+	ret = at91_sdhci_send_command(&priv->host, &cmd, NULL);
+	if (ret)
+		return ret;
+
+	*ocr = cmd.response[0];
+
+	return 0;
+}
+
+static int mmc_verify_operating_condition(struct at91_sdhci_priv *priv)
+{
+	unsigned int ocr = 0;
+	unsigned int retries = 1000;
+	unsigned int i;
+	int ret;
+
+	/* Query the card and determine the voltage type of the card */
+	ret = mmc_cmd_send_op_cond(priv, &ocr);
+	if (ret)
+		return ret;
+
+	ocr |= OCR_ACCESS_MODE_SECTOR;
+
+	for (i = 0; i < retries; i++) {
+		ret = mmc_cmd_send_op_cond(priv, &ocr);
+		if (ret)
+			return ret;
+
+		if (ocr  & (0x01U << 31))
+			break;
+
+		early_udelay(1000);
+	};
+
+	if (i == retries)
+		return -EIO;
+
+	pr_debug("mmc_verify_operating_condition success OCR = %x\n", ocr);
+	return 0;
+}
+
+/*
+ * Refer to Physical Layer Specification Version 3.1
+ * Figure 4-1: SD Memory Card State Diagram (card identification mode)
+ * Figure 4-2: Card Initialization and Indentification Flow (SD mode)
+ */
+static int sdcard_identification(struct at91_sdhci_priv *priv)
+{
+	int ret;
+
+	early_udelay(3000);
+
+	ret = sd_cmd_go_idle_state(priv);
+	if (ret)
+		return ret;
+
+	early_udelay(2000);
+
+	ret = mmc_verify_operating_condition(priv);
+	if (ret == 0) {
+		priv->no_sd = true;
+	} else if (ret == -ETIMEDOUT) {
+		ret = sd_cmd_send_if_cond(priv);
+		if (ret == 0) /* Ver 2.00 or later SD Memory Card */
+			ret = sd_check_operational_condition(priv, 1);
+		else if (ret == -ETIMEDOUT)
+			ret = sd_check_operational_condition(priv, 0);
+	}
+
+	if (ret) {
+		pr_warn("Unusable Card\n");
+		return ret;
+	}
+
+	priv->highcapacity_card = priv->ocr & OCR_HCS ? 1 : 0;
+
+	/*
+	 * Card that is unidentified (which is in Ready State)
+	 * sends its CID number
+	 */
+	ret = sd_cmd_all_send_cid(priv);
+	if (ret) {
+		pr_warn("sd_cmd_all_send_cid failed\n");
+		return ret;
+	}
+
+	/* Asks the card to publish a new relative card address (RCA) */
+	ret = sd_cmd_send_relative_addr(priv);
+	if (ret) {
+		pr_warn("sd_cmd_send_relative_addr failed\n");
+		return ret;
+	}
+
+	pr_debug("sdcard_identification success\n");
+	return 0;
+}
+
+
+static struct at91_sdhci_priv atmel_sdcard;
+
+int atmel_sdhci_bio_init(struct pbl_bio *bio, void __iomem *base)
+{
+	struct at91_sdhci_priv *priv = &atmel_sdcard;
+	struct at91_sdhci *host = &priv->host;
+	int ret;
+
+	bio->priv = priv;
+	bio->read = atmel_sdhci_bio_read;
+
+	atmel_sdhci_prep(host, base);
+
+	at91_sdhci_host_capability(host, &priv->voltages);
+
+	if (!at91_sdhci_is_card_inserted(host)) {
+		pr_err("SDHC: No Card Inserted\n");
+		return -ENODEV;
+	}
+
+	ret = atmel_sdhci_init(host);
+	if (ret)
+		return ret;
+
+	/* Card Indentification Mode */
+	ret = sdcard_identification(priv);
+	if (ret)
+		return ret;
+
+	return sd_cmd_select_card(priv);
+}
diff --git a/drivers/mci/atmel-sdhci.h b/drivers/mci/atmel-sdhci.h
new file mode 100644
index 000000000000..fb4c0e346e7d
--- /dev/null
+++ b/drivers/mci/atmel-sdhci.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+
+#ifndef ATMEL_SDHCI_H_
+#define ATMEL_SDHCI_H_
+
+#include <linux/types.h>
+#include <mci.h>
+
+#include "sdhci.h"
+
+struct at91_sdhci {
+	struct sdhci	sdhci;
+	void __iomem	*base;
+};
+
+/*
+ * Response Types
+ */
+#define	SD_RESP_TYPE_NO_RESP	0x00
+#define	SD_RESP_TYPE_R1		0x10
+#define	SD_RESP_TYPE_R1B	0x11
+#define	SD_RESP_TYPE_R2		0x20
+#define	SD_RESP_TYPE_R3		0x30
+#define	SD_RESP_TYPE_R4		0x40
+#define	SD_RESP_TYPE_R5		0x50
+#define	SD_RESP_TYPE_R6		0x60
+#define	SD_RESP_TYPE_R7		0x70
+
+int atmel_sdhci_init(struct at91_sdhci *host);
+void atmel_sdhci_prep(struct at91_sdhci *host, void __iomem *base);
+int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *sd_cmd,
+			    struct mci_data *data);
+bool at91_sdhci_is_card_inserted(struct at91_sdhci *host);
+void at91_sdhci_host_capability(struct at91_sdhci *host,
+				unsigned int *voltages);
+
+#endif
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index a307dc97cd9a..48dc3f36530c 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -38,6 +38,7 @@
 #define SDHCI_RESPONSE_1					0x14
 #define SDHCI_RESPONSE_2					0x18
 #define SDHCI_RESPONSE_3					0x1c
+#define SDHCI_RESPONSE(i)					(SDHCI_RESPONSE_0 + 4 * (i))
 #define SDHCI_BUFFER						0x20
 #define SDHCI_PRESENT_STATE					0x24
 #define  SDHCI_WRITE_PROTECT			BIT(19)
@@ -53,6 +54,7 @@
 #define  SDHCI_CARD_DETECT_SIGNAL_SELECTION	BIT(7)
 #define  SDHCI_CARD_DETECT_TEST_LEVEL		BIT(6)
 #define  SDHCI_DATA_WIDTH_8BIT			BIT(5)
+#define  SDHCI_DMASEL_ADMA32			BIT(4)
 #define  SDHCI_HIGHSPEED_EN			BIT(2)
 #define  SDHCI_DATA_WIDTH_4BIT			BIT(1)
 #define SDHCI_POWER_CONTROL					0x29
@@ -68,8 +70,11 @@
 #define SDHCI_TIMEOUT_CONTROL					0x2e
 #define SDHCI_SOFTWARE_RESET					0x2f
 #define  SDHCI_RESET_ALL			BIT(0)
+#define  SDHCI_RESET_CMD			BIT(1)
+#define  SDHCI_RESET_DATA			BIT(2)
 #define SDHCI_INT_STATUS					0x30
 #define SDHCI_INT_NORMAL_STATUS					0x30
+#define  SDHCI_INT_ERROR_ADMA			BIT(25)
 #define  SDHCI_INT_DATA_END_BIT			BIT(22)
 #define  SDHCI_INT_DATA_CRC			BIT(21)
 #define  SDHCI_INT_DATA_TIMEOUT			BIT(20)
@@ -79,6 +84,7 @@
 #define  SDHCI_INT_TIMEOUT			BIT(16)
 #define  SDHCI_INT_ERROR			BIT(15)
 #define  SDHCI_INT_CARD_INT			BIT(8)
+#define  SDHCI_INT_CARD_INSERT			BIT(6)
 #define  SDHCI_INT_DATA_AVAIL			BIT(5)
 #define  SDHCI_INT_SPACE_AVAIL			BIT(4)
 #define  SDHCI_INT_DMA				BIT(3)
@@ -86,7 +92,11 @@
 #define  SDHCI_INT_CMD_COMPLETE			BIT(0)
 #define SDHCI_INT_ERROR_STATUS					0x32
 #define SDHCI_INT_ENABLE					0x34
+#define SDHCI_INT_NORMAL_ENABLE					0x34
+#define SDHCI_INT_ERROR_ENABLE					0x36
 #define SDHCI_SIGNAL_ENABLE					0x38
+#define SDHCI_SIGNAL_NORMAL_ENABLE				0x38
+#define SDHCI_SIGNAL_ERROR_ENABLE				0x3a
 #define SDHCI_ACMD12_ERR__HOST_CONTROL2				0x3C
 #define SDHCI_CAPABILITIES					0x40
 #define SDHCI_CAPABILITIES_1					0x42
@@ -96,6 +106,13 @@
 #define  SDHCI_HOSTCAP_HIGHSPEED		BIT(5)
 #define  SDHCI_HOSTCAP_8BIT			BIT(2)
 
+#define SDHCI_PRESET_FOR_SDR12					0x66
+#define SDHCI_PRESET_FOR_SDR25					0x68
+#define SDHCI_PRESET_FOR_SDR50					0x6A
+#define SDHCI_PRESET_FOR_SDR104					0x6C
+#define SDHCI_PRESET_FOR_DDR50					0x6E
+#define SDHCI_PRESET_FOR_HS400					0x74 /* Non-standard */
+
 #define SDHCI_SPEC_200_MAX_CLK_DIVIDER	256
 #define SDHCI_MMC_BOOT						0xC4
 
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC PATCH 4/5] ARM: at91: add helpers for MCI barebox chain-loading
  2020-01-06 17:35 [RFC PATCH 0/5] fs: fat: extend for in-PBL support Ahmad Fatoum
                   ` (2 preceding siblings ...)
  2020-01-06 17:35 ` [RFC PATCH 3/5] mci: add first-stage at91-sdhci driver Ahmad Fatoum
@ 2020-01-06 17:35 ` Ahmad Fatoum
  2020-01-06 17:35 ` [RFC PATCH 5/5] [WIP] ARM: at91: sama5d27-som1: add first stage entry point Ahmad Fatoum
  4 siblings, 0 replies; 8+ messages in thread
From: Ahmad Fatoum @ 2020-01-06 17:35 UTC (permalink / raw)
  To: barebox; +Cc: lst

With PBL FAT support implemented, provide an sama5d2_sdhci_start_image
helper that cann called from the PBL to chainload a barebox.bin file
from the first FAT partition.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 arch/arm/mach-at91/Kconfig              |  5 +++
 arch/arm/mach-at91/Makefile             |  1 +
 arch/arm/mach-at91/include/mach/xload.h | 12 ++++++
 arch/arm/mach-at91/xload-mmc.c          | 51 +++++++++++++++++++++++++
 4 files changed, 69 insertions(+)
 create mode 100644 arch/arm/mach-at91/include/mach/xload.h
 create mode 100644 arch/arm/mach-at91/xload-mmc.c

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 5267102bf94e..a14aa59773fa 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -34,6 +34,11 @@ config HAVE_AT91_GENERATED_CLK
 config HAVE_AT91_BOOTSTRAP
 	bool
 
+config AT91_MCI_PBL
+	bool
+	depends on MCI_ATMEL_SDHCI_PBL
+	default y
+
 # Select if board uses the common at91sam926x_board_init
 config AT91SAM926X_BOARD_INIT
 	bool
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 66d0b700f61e..8db30f338c37 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_AT91_BOOTSTRAP)	+= bootstrap.o
 
 obj-y += at91sam9_reset.o
 obj-y += at91sam9g45_reset.o
+pbl-$(CONFIG_AT91_MCI_PBL) +=  xload-mmc.o
 
 obj-$(CONFIG_AT91SAM9_SMC) += sam9_smc.o
 
diff --git a/arch/arm/mach-at91/include/mach/xload.h b/arch/arm/mach-at91/include/mach/xload.h
new file mode 100644
index 000000000000..d73be6d45f67
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/xload.h
@@ -0,0 +1,12 @@
+#ifndef __MACH_XLOAD_H
+#define __MACH_XLOAD_H
+
+#include <linux/compiler.h>
+#include <pbl.h>
+
+void __noreturn sama5d2_sdhci_start_image(int instance);
+
+int atmel_sdhci_bio_init(struct pbl_bio *bio, void __iomem *base);
+
+#endif /* __MACH_XLOAD_H */
+
diff --git a/arch/arm/mach-at91/xload-mmc.c b/arch/arm/mach-at91/xload-mmc.c
new file mode 100644
index 000000000000..adb260f40e33
--- /dev/null
+++ b/arch/arm/mach-at91/xload-mmc.c
@@ -0,0 +1,51 @@
+#include <common.h>
+#include <mach/xload.h>
+#include <mach/hardware.h>
+#include <asm/barebox-arm.h>
+#include <linux/sizes.h> // FIXME remove
+#include <asm/cache.h>
+#include <pbl.h>
+#include <debug_ll.h>
+
+static void at91_fat_start_image(struct pbl_bio *bio, void *buf, unsigned int len)
+{
+	void __noreturn (*bb)(void);
+	int ret;
+
+	ret = pbl_fat_load(bio, "barebox.bin", buf, len);
+	if (ret) {
+		pr_err("pbl_fat_load: error %d\n", ret);
+		return;
+	}
+
+	bb = buf;
+
+	sync_caches_for_execution();
+
+	bb();
+}
+
+/**
+ * sama5d2_sdhci_start_image - Load and start an image from FAT-formatted SDHCI
+ * @instance: The SDHCI instance {0,1}
+ *
+ * Return: If successul, this function does not return. A negative error
+ * code is returned when this function fails.
+ */
+void __noreturn sama5d2_sdhci_start_image(int instance)
+{
+	void *buf = (void *)SAMA5_DDRCS + SZ_64M;
+	void __iomem *base;
+	struct pbl_bio bio;
+	int ret;
+
+	base = IOMEM(instance ? SAMA5D2_BASE_SDHC1 : SAMA5D2_BASE_SDHC0);
+	ret = atmel_sdhci_bio_init(&bio, base);
+	if (ret)
+		goto out_panic;
+
+	at91_fat_start_image(&bio, buf, SZ_64M);
+
+out_panic:
+	panic("FAT chainloading failed\n");
+}
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [RFC PATCH 5/5] [WIP] ARM: at91: sama5d27-som1: add first stage entry point
  2020-01-06 17:35 [RFC PATCH 0/5] fs: fat: extend for in-PBL support Ahmad Fatoum
                   ` (3 preceding siblings ...)
  2020-01-06 17:35 ` [RFC PATCH 4/5] ARM: at91: add helpers for MCI barebox chain-loading Ahmad Fatoum
@ 2020-01-06 17:35 ` Ahmad Fatoum
  4 siblings, 0 replies; 8+ messages in thread
From: Ahmad Fatoum @ 2020-01-06 17:35 UTC (permalink / raw)
  To: barebox; +Cc: lst

This commit is only for testing purposes. It will be submitted later,
when SDRAM setup for the sama5d2 is implemented as well.

Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
---
 arch/arm/boards/sama5d27-som1/lowlevel.c | 16 ++++++++++++++++
 arch/arm/mach-at91/Kconfig               |  1 +
 images/Makefile.at91                     |  4 ++++
 3 files changed, 21 insertions(+)

diff --git a/arch/arm/boards/sama5d27-som1/lowlevel.c b/arch/arm/boards/sama5d27-som1/lowlevel.c
index 7df5a4772d0b..da3ca1ba40a8 100644
--- a/arch/arm/boards/sama5d27-som1/lowlevel.c
+++ b/arch/arm/boards/sama5d27-som1/lowlevel.c
@@ -12,6 +12,7 @@
 
 #include <mach/hardware.h>
 #include <mach/iomux.h>
+#include <mach/xload.h>
 #include <debug_ll.h>
 #include <mach/at91_dbgu.h>
 
@@ -79,3 +80,18 @@ ENTRY_FUNCTION(start_sama5d27_som1_ek, r0, r1, r2)
 	ek_turn_led(RGB_LED_GREEN);
 	barebox_arm_entry(SAMA5_DDRCS, SZ_128M, fdt);
 }
+
+ENTRY_FUNCTION(start_sama5d27_som1_ek_xload_mmc, r0, r1, r2)
+{
+	arm_cpu_lowlevel_init();
+
+	arm_setup_stack(SAMA5D2_SRAM_BASE + SAMA5D2_SRAM_SIZE - 16);
+
+	relocate_to_current_adr();
+	setup_c();
+
+	if (IS_ENABLED(CONFIG_DEBUG_LL))
+		ek_dbgu_init();
+
+	sama5d2_sdhci_start_image(1);
+}
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index a14aa59773fa..502151ad3c24 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -583,6 +583,7 @@ config MACH_SAMA5D27_SOM1
 	bool "Microchip SAMA5D27 SoM-1 Evaluation Kit"
 	select SOC_SAMA5D2
 	select OFDEVICE
+	select MCI_ATMEL_SDHCI_PBL
 	select COMMON_CLK_OF_PROVIDER
 	help
 	  Select this if you are using Microchip's sama5d27 SoM evaluation kit
diff --git a/images/Makefile.at91 b/images/Makefile.at91
index f321bdec3696..235893c7deb9 100644
--- a/images/Makefile.at91
+++ b/images/Makefile.at91
@@ -17,3 +17,7 @@ image-$(CONFIG_MACH_MICROCHIP_KSZ9477_EVB) += barebox-microchip-ksz9477-evb.img
 pblb-$(CONFIG_MACH_SAMA5D27_SOM1) += start_sama5d27_som1_ek
 FILE_barebox-sama5d27-som1-ek.img = start_sama5d27_som1_ek.pblb
 image-$(CONFIG_MACH_SAMA5D27_SOM1) += barebox-sama5d27-som1-ek.img
+
+pblb-$(CONFIG_MACH_SAMA5D27_SOM1) += start_sama5d27_som1_ek_xload_mmc
+FILE_barebox-sama5d27-som1-ek-xload-mmc.img = start_sama5d27_som1_ek_xload_mmc.pblb
+image-$(CONFIG_MACH_SAMA5D27_SOM1) += barebox-sama5d27-som1-ek-xload-mmc.img
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 2/5] fs: fat: extend for in-PBL support
  2020-01-06 17:35 ` [RFC PATCH 2/5] fs: fat: extend for in-PBL support Ahmad Fatoum
@ 2020-01-08 11:14   ` Sascha Hauer
  0 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-01-08 11:14 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, lst

On Mon, Jan 06, 2020 at 06:35:37PM +0100, Ahmad Fatoum wrote:
> The AT91 BootROM loads a boot.bin file from the first FAT partition
> into SRAM, when booting from MMC. To avoid the need for two barebox
> configurations for each of the bootloader stages, add PBL support
> for reading from FAT. This way each stage need only have a different
> PBL entry point.
> 
> Signed-off-by: Ahmad Fatoum <ahmad@a3f.at>
> ---
>  fs/Makefile      |   2 +-
>  fs/fat/Kconfig   |   7 +++
>  fs/fat/Makefile  |   4 +-
>  fs/fat/diskio.h  |   7 ++-
>  fs/fat/fat-pbl.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++
>  fs/fat/ff.c      | 104 +++++++++++++++++++--------------
>  fs/fat/ff.h      |  17 ++++--
>  include/pbl.h    |   1 +
>  8 files changed, 237 insertions(+), 53 deletions(-)
>  create mode 100644 fs/fat/fat-pbl.c
> 
> diff --git a/fs/Makefile b/fs/Makefile
> index 9889a6507c1b..89ccc8947dc0 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -4,7 +4,7 @@ obj-$(CONFIG_FS_RAMFS)	+= ramfs.o
>  obj-y			+= devfs-core.o
>  obj-$(CONFIG_FS_LEGACY) += legacy.o
>  obj-$(CONFIG_FS_DEVFS)	+= devfs.o
> -obj-$(CONFIG_FS_FAT)	+= fat/
> +obj-pbl-$(CONFIG_FS_FAT)	+= fat/
>  obj-y	+= fs.o libfs.o
>  obj-$(CONFIG_FS_UBIFS)	+= ubifs/
>  obj-$(CONFIG_FS_TFTP)	+= tftp.o
> diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig
> index b1def851cfb8..bc3b4b69e870 100644
> --- a/fs/fat/Kconfig
> +++ b/fs/fat/Kconfig
> @@ -8,9 +8,16 @@ if FS_FAT
>  config FS_FAT_WRITE
>  	bool
>  	prompt "FAT write support"
> +	help
> +	  Enable support for writing in FAT partitions.
> +	  Note: This doesn't apply to FAT usage in barebox PBL.
> +
>  
>  config FS_FAT_LFN
>  	bool
>  	prompt "Support long filenames"
> +	help
> +	  Enable support for file names other than 8.3.
> +	  Note: This doesn't apply to FAT usage in barebox PBL.
>  
>  endif
> diff --git a/fs/fat/Makefile b/fs/fat/Makefile
> index efc89ec67db8..2a8a787d5438 100644
> --- a/fs/fat/Makefile
> +++ b/fs/fat/Makefile
> @@ -1 +1,3 @@
> -obj-y += ff.o fat.o
> +obj-y += fat.o
> +pbl-y += fat-pbl.o
> +obj-pbl-y += ff.o
> diff --git a/fs/fat/diskio.h b/fs/fat/diskio.h
> index f0d29dc390d5..aee1ce2b0b3b 100644
> --- a/fs/fat/diskio.h
> +++ b/fs/fat/diskio.h
> @@ -4,7 +4,12 @@
>  
>  #ifndef _DISKIO
>  
> -#define _READONLY	0	/* 1: Remove write functions */
> +#ifdef __PBL__
> +#define _READONLY	1	/* 1: Remove write functions */
> +#else
> +#define _READONLY	0
> +#endif
> +
>  #define _USE_IOCTL	1	/* 1: Use disk_ioctl fucntion */
>  
>  #include "integer.h"
> diff --git a/fs/fat/fat-pbl.c b/fs/fat/fat-pbl.c
> new file mode 100644
> index 000000000000..bd158bff8278
> --- /dev/null
> +++ b/fs/fat/fat-pbl.c
> @@ -0,0 +1,148 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * fat.c - FAT filesystem barebox driver
> + *
> + * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
> + */
> +
> +#define pr_fmt(fmt) "fat-pbl: " fmt
> +
> +#include <common.h>
> +#include "integer.h"
> +#include "ff.h"
> +#include "diskio.h"
> +#include "pbl.h"
> +
> +/* ---------------------------------------------------------------*/
> +
> +DRESULT disk_read(FATFS *fat, BYTE *buf, DWORD sector, BYTE count)
> +{
> +	struct pbl_bio *bio = fat->userdata;
> +	int ret;
> +
> +	debug("%s: sector: %ld count: %d\n", __func__, sector, count);
> +
> +	ret = bio->read(bio, sector, buf, count);
> +	if (ret != count)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +DSTATUS disk_status(FATFS *fat)
> +{
> +	return 0;
> +}
> +
> +DWORD get_fattime(void)
> +{
> +	return 0;
> +}
> +
> +DRESULT disk_ioctl (FATFS *fat, BYTE command, void *buf)
> +{
> +	return 0;
> +}
> +
> +WCHAR ff_convert(WCHAR src, UINT dir)
> +{
> +	if (src <= 0x80)
> +		return src;
> +	else
> +		return '?';
> +}
> +
> +WCHAR ff_wtoupper(WCHAR chr)
> +{
> +	if (chr > 0x80)
> +		return '?';
> +
> +	if ('a' <= chr && chr <= 'z')
> +		return  chr + 'A' - 'a';
> +
> +	return chr;
> +}
> +
> +static int fat_loadimage(FATFS *fs, const char *filename, void *dest, unsigned int len)
> +{
> +	FIL	file = {};
> +	UINT	nread;
> +	int	ret;
> +
> +	ret = f_open(fs, &file, filename, FA_OPEN_EXISTING | FA_READ);
> +	if (ret) {
> +		pr_debug("f_open(%s) failed: %d\n", filename, ret);
> +		return ret;
> +	}
> +
> +	ret = f_read(&file, dest, len, &nread);
> +	if (ret) {
> +		pr_debug("f_read failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	if (f_size(&file) > len)
> +		return -ENOSPC;
> +
> +	return 0;
> +}
> +
> +int pbl_fat_load(struct pbl_bio *bio, const char *filename, void *dest, unsigned int len)
> +{
> +	FATFS	fs = {};
> +	int	ret;
> +
> +	fs.userdata = bio;
> +
> +	/* mount fs */
> +	ret = f_mount(&fs);
> +	if (ret) {
> +		pr_debug("f_mount(%s) failed: %d\n", filename, ret);
> +		return ret;
> +	}
> +
> +	pr_debug("Reading file %s to 0x%p\n", filename, dest);
> +
> +	return fat_loadimage(&fs, filename, dest, len);
> +}
> +
> +#define BS_55AA                     510     /* Boot sector signature (2) */
> +#define BS_FilSysType               54      /* File system type (1) */
> +#define BS_FilSysType32             82      /* File system type (1) */
> +#define MBR_Table           446     /* MBR: Partition table offset (2) */
> +#define MBR_StartSector             8
> +
> +enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec)
> +{
> +	/*
> +	 * bootsec can be used to return index of the first sector in the
> +	 * first partition
> +	 */
> +	if (bootsec)
> +		*bootsec = 0;
> +
> +	/*
> +	 * Check record signature (always placed at offset 510 even if the
> +	 * sector size is > 512)
> +	 */
> +	if (get_unaligned_le16(&sector[BS_55AA]) != 0xAA55)
> +		return filetype_unknown;
> +
> +	/* Check "FAT" string */
> +	if ((get_unaligned_le32(&sector[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
> +		return filetype_fat;
> +
> +	if ((get_unaligned_le32(&sector[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
> +		return filetype_fat;
> +
> +	if (bootsec)
> +		/*
> +		 * This must be an MBR, so return the starting sector of the
> +		 * first partition so we could check if there is a FAT boot
> +		 * sector there
> +		 */
> +		*bootsec = get_unaligned_le16(&sector[MBR_Table + MBR_StartSector]);
> +
> +	return filetype_mbr;
> +}
> +
> diff --git a/fs/fat/ff.c b/fs/fat/ff.c
> index 4d30433e5f03..29e4c8adb614 100644
> --- a/fs/fat/ff.c
> +++ b/fs/fat/ff.c
> @@ -92,10 +92,24 @@
>  #include <string.h>
>  #include <errno.h>
>  #include <malloc.h>
> -#include <linux/ctype.h>
>  #include <filetype.h>
>  #include "ff.h"			/* FatFs configurations and declarations */
>  #include "diskio.h"		/* Declarations of low level disk I/O functions */
> +#include <pbl.h>
> +
> +#ifndef __PBL__
> +#include <linux/ctype.h>
> +#else
> +static inline int isupper(int ch)
> +{
> +	return 'A' <= ch && ch <= 'Z';
> +}
> +
> +static inline int islower(int ch)
> +{
> +	return 'a' <= ch && ch <= 'z';
> +}
> +#endif

Better compile lib/ctype.c for pbl as well and use standard
linux/ctype.h for pbl?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH 3/5] mci: add first-stage at91-sdhci driver
  2020-01-06 17:35 ` [RFC PATCH 3/5] mci: add first-stage at91-sdhci driver Ahmad Fatoum
@ 2020-01-08 11:23   ` Sascha Hauer
  0 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-01-08 11:23 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox, lst

On Mon, Jan 06, 2020 at 06:35:38PM +0100, Ahmad Fatoum wrote:
> diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
> index a307dc97cd9a..48dc3f36530c 100644
> --- a/drivers/mci/sdhci.h
> +++ b/drivers/mci/sdhci.h
> @@ -38,6 +38,7 @@
>  #define SDHCI_RESPONSE_1					0x14
>  #define SDHCI_RESPONSE_2					0x18
>  #define SDHCI_RESPONSE_3					0x1c
> +#define SDHCI_RESPONSE(i)					(SDHCI_RESPONSE_0 + 4 * (i))
>  #define SDHCI_BUFFER						0x20
>  #define SDHCI_PRESENT_STATE					0x24
>  #define  SDHCI_WRITE_PROTECT			BIT(19)
> @@ -53,6 +54,7 @@
>  #define  SDHCI_CARD_DETECT_SIGNAL_SELECTION	BIT(7)
>  #define  SDHCI_CARD_DETECT_TEST_LEVEL		BIT(6)
>  #define  SDHCI_DATA_WIDTH_8BIT			BIT(5)
> +#define  SDHCI_DMASEL_ADMA32			BIT(4)

Have you verified that all bits you add in this file are valid for the
generic SDHCI controller? There shouldn't be any Atmel specific bits
between them.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-01-08 11:23 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-06 17:35 [RFC PATCH 0/5] fs: fat: extend for in-PBL support Ahmad Fatoum
2020-01-06 17:35 ` [RFC PATCH 1/5] pbl: add block I/O API Ahmad Fatoum
2020-01-06 17:35 ` [RFC PATCH 2/5] fs: fat: extend for in-PBL support Ahmad Fatoum
2020-01-08 11:14   ` Sascha Hauer
2020-01-06 17:35 ` [RFC PATCH 3/5] mci: add first-stage at91-sdhci driver Ahmad Fatoum
2020-01-08 11:23   ` Sascha Hauer
2020-01-06 17:35 ` [RFC PATCH 4/5] ARM: at91: add helpers for MCI barebox chain-loading Ahmad Fatoum
2020-01-06 17:35 ` [RFC PATCH 5/5] [WIP] ARM: at91: sama5d27-som1: add first stage entry point Ahmad Fatoum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox