* [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(§or[BS_55AA]) != 0xAA55)
+ return filetype_unknown;
+
+ /* Check "FAT" string */
+ if ((get_unaligned_le32(§or[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
+ return filetype_fat;
+
+ if ((get_unaligned_le32(§or[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(§or[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
* 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(§or[BS_55AA]) != 0xAA55)
> + return filetype_unknown;
> +
> + /* Check "FAT" string */
> + if ((get_unaligned_le32(§or[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
> + return filetype_fat;
> +
> + if ((get_unaligned_le32(§or[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(§or[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
* [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
* 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
* [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