Skip to contentSkip to conversation

ARM: kirkwood: add mvsdio driver

PATCH Superseded Gerald Kerma 3 participants 4 messages Jul 24, 2014 – Jul 25, 2014

Subsystems (2)

v4 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/1 ARM: kirkwood: add mvsdio driver

---
Changes in v4:
- rename drivers files to MVSDIO
- fix MMC clock init which now use dev ID
- clean debug strings
- remove MVSDIO_TWEAK_NOSDHS quirk
- remove dead code

Changes in v3:
- Add MVSDIO_TWEAK_NOSDHS quirk
- Minor clean

Changes in v2:
- Fix some typo and missing lines from patch import

 arch/arm/cpu/arm926ejs/kirkwood/cpu.c          |  58 ++++
 arch/arm/include/asm/arch-kirkwood/config.h    |   2 +
 arch/arm/include/asm/arch-kirkwood/cpu.h       |   2 +
 arch/arm/include/asm/arch-kirkwood/kirkwood.h  |  24 ++
 arch/arm/include/asm/arch-kirkwood/kw88f6282.h |  33 +++
 board/Marvell/openrd/openrd.c                  |  11 +
 board/Marvell/sheevaplug/sheevaplug.c          |  11 +
 drivers/mmc/Makefile                           |   1 +
 drivers/mmc/mvsdio.c                           | 384 +++++++++++++++++++++++++
 include/configs/openrd.h                       |   8 +
 include/configs/sheevaplug.h                   |  19 +-
 include/mvsdio.h                               | 279 ++++++++++++++++++
 12 files changed, 830 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-kirkwood/kw88f6282.h
 create mode 100644 drivers/mmc/mvsdio.c
 create mode 100644 include/mvsdio.h
arch/arm/cpu/arm926ejs/kirkwood/cpu.c +58 -0
index da80240..472aa8a 100644
@@ -333,6 +333,64 @@ int arch_cpu_init(void)
 }
 #endif /* CONFIG_ARCH_CPU_INIT */
 
+/*****************************************************************************
+ * General
+ ****************************************************************************/
+#if defined(CONFIG_ARCH_DEV_ID)
+
+void kirkwood_pcie_id(u32 *dev, u32 *rev)
+{
+	*dev = (readl(KW_REG_PCIE_DEVID) >> 16) & 0xffff;
+	*rev = readl(KW_REG_PCIE_REVID) & 0xff;
+}
+
+/*
+ * Identify device ID and revision.
+ */
+char *kirkwood_id(void)
+{
+	u32 dev, rev;
+
+	kirkwood_pcie_id(&dev, &rev);
+
+	if (dev == MV88F6281_DEV_ID) {
+		if (rev == MV88F6281_REV_Z0)
+			return "MV88F6281-Z0";
+		else if (rev == MV88F6281_REV_A0)
+			return "MV88F6281-A0";
+		else if (rev == MV88F6281_REV_A1)
+			return "MV88F6281-A1";
+		else
+			return "MV88F6281-Rev-Unsupported";
+	} else if (dev == MV88F6192_DEV_ID) {
+		if (rev == MV88F6192_REV_Z0)
+			return "MV88F6192-Z0";
+		else if (rev == MV88F6192_REV_A0)
+			return "MV88F6192-A0";
+		else if (rev == MV88F6192_REV_A1)
+			return "MV88F6192-A1";
+		else
+			return "MV88F6192-Rev-Unsupported";
+	} else if (dev == MV88F6180_DEV_ID) {
+		if (rev == MV88F6180_REV_A0)
+			return "MV88F6180-Rev-A0";
+		else if (rev == MV88F6180_REV_A1)
+			return "MV88F6180-Rev-A1";
+		else
+			return "MV88F6180-Rev-Unsupported";
+	} else if (dev == MV88F6282_DEV_ID) {
+		if (rev == MV88F6282_REV_A0)
+			return "MV88F6282-Rev-A0";
+		else if (rev == MV88F6282_REV_A1)
+			return "MV88F6282-Rev-A1";
+		else
+			return "MV88F6282-Rev-Unsupported";
+	} else {
+		return "Device-Unknown";
+	}
+}
+#endif /* CONFIG_ARCH_DEV_ID */
+
 /*
  * SOC specific misc init
  */
arch/arm/include/asm/arch-kirkwood/config.h +2 -0
index 7a688e4..a0563a3 100644
@@ -19,6 +19,8 @@
 #include <asm/arch/kw88f6281.h>
 #elif defined (CONFIG_KW88F6192)
 #include <asm/arch/kw88f6192.h>
+#elif defined(CONFIG_KW88F6182)
+#include <asm/arch/kw88f6182.h>
 #else
 #error "SOC Name not defined"
 #endif /* CONFIG_KW88F6281 */
arch/arm/include/asm/arch-kirkwood/cpu.h +2 -0
index 97daa40..e7b6448 100644
@@ -151,5 +151,7 @@ int kw_config_mpp(unsigned int mpp0_7, unsigned int mpp8_15,
 		unsigned int mpp32_39, unsigned int mpp40_47,
 		unsigned int mpp48_55);
 unsigned int kw_winctrl_calcsize(unsigned int sizeval);
+void kirkwood_pcie_id(u32 *dev, u32 *rev);
+char *kirkwood_id(void);
 #endif /* __ASSEMBLY__ */
 #endif /* _KWCPU_H */
arch/arm/include/asm/arch-kirkwood/kirkwood.h +24 -0
index bc207f5..489517f 100644
@@ -39,6 +39,7 @@
 #define KW_EGIGA0_BASE			(KW_REGISTER(0x72000))
 #define KW_EGIGA1_BASE			(KW_REGISTER(0x76000))
 #define KW_SATA_BASE			(KW_REGISTER(0x80000))
+#define KW_SDIO_BASE			(KW_REGISTER(0x90000))
 
 /* Kirkwood Sata controller has two ports */
 #define KW_SATA_PORT0_OFFSET		0x2000
@@ -61,10 +62,33 @@
 #define MVCPU_WIN_ENABLE	KWCPU_WIN_ENABLE
 #define MVCPU_WIN_DISABLE	KWCPU_WIN_DISABLE
 
+/*
+ * Supported devices and revisions.
+ */
+#define MV88F6281_DEV_ID	0x6281
+#define MV88F6281_REV_Z0	0
+#define MV88F6281_REV_A0	2
+#define MV88F6281_REV_A1	3
+
+#define MV88F6192_DEV_ID	0x6192
+#define MV88F6192_REV_Z0	0
+#define MV88F6192_REV_A0	2
+#define MV88F6192_REV_A1	3
+
+#define MV88F6180_DEV_ID	0x6180
+#define MV88F6180_REV_A0	2
+#define MV88F6180_REV_A1	3
+
+#define MV88F6282_DEV_ID	0x6282
+#define MV88F6282_REV_A0	0
+#define MV88F6282_REV_A1	1
+
 #if defined (CONFIG_KW88F6281)
 #include <asm/arch/kw88f6281.h>
 #elif defined (CONFIG_KW88F6192)
 #include <asm/arch/kw88f6192.h>
+#elif defined(CONFIG_KW88F6182)
+#include <asm/arch/kw88f6182.h>
 #else
 #error "SOC Name not defined"
 #endif /* CONFIG_KW88F6281 */
arch/arm/include/asm/arch-kirkwood/kw88f6282.h new file +33 -0
new file mode 100644
index 0000000..5310da2
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <[email protected]>
+ *
+ * Header file for Feroceon CPU core 88FR131 Based KW88F6281 SOC.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ASM_ARCH_KW88F6281_H
+#define _ASM_ARCH_KW88F6281_H
+
+/* SOC specific definitions */
+#define KW88F6281_REGS_PHYS_BASE	0xf1000000
+#define KW_REGS_PHY_BASE		KW88F6281_REGS_PHYS_BASE
+
+/* TCLK Core Clock definition */
+#ifndef CONFIG_SYS_TCLK
+#define CONFIG_SYS_TCLK	200000000 /* 200MHz */
+#endif
+
board/Marvell/openrd/openrd.c +11 -0
index a005a2f..6e9dca6 100644
@@ -17,6 +17,9 @@
 #include <asm/arch/kirkwood.h>
 #include <asm/arch/mpp.h>
 #include "openrd.h"
+#ifdef CONFIG_MVSDIO_MMC
+# include <mvsdio.h>
+#endif /* CONFIG_MVSDIO_MMC */
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -159,3 +162,11 @@ void reset_phy(void)
 #endif
 }
 #endif /* CONFIG_RESET_PHY_R */
+
+#ifdef CONFIG_MRVL_MMC
+int board_mmc_init(bd_t *bis)
+{
+	mrvl_mmc_init(bis);
+	return 0;
+}
+#endif /* CONFIG_MRVL_MMC */
board/Marvell/sheevaplug/sheevaplug.c +11 -0
index 87e49f4..c33f55c 100644
@@ -12,6 +12,9 @@
 #include <asm/arch/kirkwood.h>
 #include <asm/arch/mpp.h>
 #include "sheevaplug.h"
+#ifdef CONFIG_MVSDIO_MMC
+# include <mvsdio.h>
+#endif /* CONFIG_MVSDIO_MMC */
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -131,3 +134,11 @@ void reset_phy(void)
 	printf("88E1116 Initialized on %s\n", name);
 }
 #endif /* CONFIG_RESET_PHY_R */
+
+#ifdef CONFIG_MRVL_MMC
+int board_mmc_init(bd_t *bis)
+{
+	mrvl_mmc_init(bis);
+	return 0;
+}
+#endif /* CONFIG_MRVL_MMC */
drivers/mmc/Makefile +1 -0
index 34febf5..1c8f275 100644
@@ -37,3 +37,4 @@ obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
 else
 obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
 endif
+obj-$(CONFIG_MVSDIO_MMC) += mvsdio.o
drivers/mmc/mvsdio.c new file +384 -0

384 lines not on this page · raw message

include/configs/openrd.h +8 -0
index 8fab6e6..03370b7 100644
@@ -49,6 +49,7 @@
 #define CONFIG_CMD_DHCP
 #define CONFIG_CMD_ENV
 #define CONFIG_CMD_MII
+#define CONFIG_CMD_MMC
 #define CONFIG_CMD_NAND
 #define CONFIG_CMD_PING
 #define CONFIG_CMD_USB
@@ -123,4 +124,11 @@
 #define CONFIG_SYS_ATA_IDE1_OFFSET	MV_SATA_PORT1_OFFSET
 #endif /*CONFIG_MVSATA_IDE*/
 
+#ifdef CONFIG_CMD_MMC
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_MVSDIO_MMC
+#define CONFIG_SYS_MMC_BASE KW_SDIO_BASE
+#endif /* CONFIG_CMD_MMC */
+
 #endif /* _CONFIG_OPENRD_BASE_H */
include/configs/sheevaplug.h +17 -2
index ecc93bc..b6ecac9 100644
@@ -23,6 +23,8 @@
 #define CONFIG_MACH_SHEEVAPLUG	/* Machine type */
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
 
+#define CONFIG_ARCH_DEV_ID	1
+
 /*
  * Commands configuration
  */
@@ -31,9 +33,11 @@
 #define CONFIG_CMD_DHCP
 #define CONFIG_CMD_ENV
 #define CONFIG_CMD_MII
+#define CONFIG_CMD_MMC
 #define CONFIG_CMD_NAND
 #define CONFIG_CMD_PING
 #define CONFIG_CMD_USB
+
 /*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros
@@ -49,13 +53,14 @@
 #else
 #define CONFIG_ENV_IS_NOWHERE		1	/* if env in SDRAM */
 #endif
+
 /*
  * max 4k env size is enough, but in case of nand
  * it has to be rounded to sector size
  */
 #define CONFIG_ENV_SIZE			0x20000	/* 128k */
-#define CONFIG_ENV_ADDR			0x60000
-#define CONFIG_ENV_OFFSET		0x60000	/* env starts here */
+#define CONFIG_ENV_ADDR			0x80000
+#define CONFIG_ENV_OFFSET		0x80000	/* env starts here */
 
 /*
  * Default environment variables
@@ -82,6 +87,16 @@
 #endif /* CONFIG_CMD_NET */
 
 /*
+ * SDIO/MMC Card Configuration
+ */
+#ifdef CONFIG_CMD_MMC
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_MVSDIO_MMC
+#define CONFIG_SYS_MMC_BASE KW_SDIO_BASE
+#endif /* CONFIG_CMD_MMC */
+
+/*
  * File system
  */
 #define CONFIG_CMD_EXT2
include/mvsdio.h new file +279 -0

279 lines not on this page · raw message

Signature · 1 line
1.9.1
#1 lore raw

PATCH v4 1/1 ARM: kirkwood: add mvsdio driver

Hi Gerald,

Quoted 8 lines · Gerald Kerma

---
Changes in v4:
- rename drivers files to MVSDIO
- fix MMC clock init which now use dev ID
- clean debug strings
- remove MVSDIO_TWEAK_NOSDHS quirk
- remove dead code

Thanks. But still some more comments below.

Quoted 79 lines

Changes in v3:
- Add MVSDIO_TWEAK_NOSDHS quirk
- Minor clean

Changes in v2:
- Fix some typo and missing lines from patch import

  arch/arm/cpu/arm926ejs/kirkwood/cpu.c          |  58 ++++
  arch/arm/include/asm/arch-kirkwood/config.h    |   2 +
  arch/arm/include/asm/arch-kirkwood/cpu.h       |   2 +
  arch/arm/include/asm/arch-kirkwood/kirkwood.h  |  24 ++
  arch/arm/include/asm/arch-kirkwood/kw88f6282.h |  33 +++
  board/Marvell/openrd/openrd.c                  |  11 +
  board/Marvell/sheevaplug/sheevaplug.c          |  11 +
  drivers/mmc/Makefile                           |   1 +
  drivers/mmc/mvsdio.c                           | 384 +++++++++++++++++++++++++
  include/configs/openrd.h                       |   8 +
  include/configs/sheevaplug.h                   |  19 +-
  include/mvsdio.h                               | 279 ++++++++++++++++++
  12 files changed, 830 insertions(+), 2 deletions(-)

create mode 100644 arch/arm/include/asm/arch-kirkwood/kw88f6282.h create mode 100644 drivers/mmc/mvsdio.c
create mode 100644 include/mvsdio.h

arch/arm/cpu/arm926ejs/kirkwood/cpu.c +47 -0
index da80240..472aa8a 100644
@@ -333,6 +333,64 @@ int arch_cpu_init(void)
  }
  #endif /* CONFIG_ARCH_CPU_INIT */
 
+/*****************************************************************************
+ * General
+ ****************************************************************************/
+#if defined(CONFIG_ARCH_DEV_ID)
+
+void kirkwood_pcie_id(u32 *dev, u32 *rev)
+{
+	*dev = (readl(KW_REG_PCIE_DEVID) >> 16) & 0xffff;
+	*rev = readl(KW_REG_PCIE_REVID) & 0xff;
+}
+
+/*
+ * Identify device ID and revision.
+ */
+char *kirkwood_id(void)
+{
+	u32 dev, rev;
+
+	kirkwood_pcie_id(&dev, &rev);
+
+	if (dev == MV88F6281_DEV_ID) {
+		if (rev == MV88F6281_REV_Z0)
+			return "MV88F6281-Z0";
+		else if (rev == MV88F6281_REV_A0)
+			return "MV88F6281-A0";
+		else if (rev == MV88F6281_REV_A1)
+			return "MV88F6281-A1";
+		else
+			return "MV88F6281-Rev-Unsupported";
+	} else if (dev == MV88F6192_DEV_ID) {
+		if (rev == MV88F6192_REV_Z0)
+			return "MV88F6192-Z0";
+		else if (rev == MV88F6192_REV_A0)
+			return "MV88F6192-A0";
+		else if (rev == MV88F6192_REV_A1)
+			return "MV88F6192-A1";
+		else
+			return "MV88F6192-Rev-Unsupported";
+	} else if (dev == MV88F6180_DEV_ID) {
+		if (rev == MV88F6180_REV_A0)
+			return "MV88F6180-Rev-A0";
+		else if (rev == MV88F6180_REV_A1)
+			return "MV88F6180-Rev-A1";
+		else
+			return "MV88F6180-Rev-Unsupported";
+	} else if (dev == MV88F6282_DEV_ID) {
+		if (rev == MV88F6282_REV_A0)

arch/arm/cpu/arm926ejs/kirkwood/cpu.c int arch_cpu_init(void) · line 392

Quoted 10 lines
arch/arm/cpu/arm926ejs/kirkwood/cpu.c +10 -0
+			return "MV88F6282-Rev-A0";
+		else if (rev == MV88F6282_REV_A1)
+			return "MV88F6282-Rev-A1";
+		else
+			return "MV88F6282-Rev-Unsupported";
+	} else {
+		return "Device-Unknown";
+	}
+}
+#endif /* CONFIG_ARCH_DEV_ID */

I still don't see why this function is needed for the MMC driver. It seems to only be used from a debug() output. I suggest to remove it from this patch to not touch the general kirkwood stuff.

Also this MMC driver should be able to support multiple Marvells SoC's, right? So calling some "kirkwood" functions doesn't seem to be generic.

Quoted 91 lines
arch/arm/cpu/arm926ejs/kirkwood/cpu.c +1 -0
+
  /*
   * SOC specific misc init
   */
arch/arm/include/asm/arch-kirkwood/config.h +2 -0
index 7a688e4..a0563a3 100644
@@ -19,6 +19,8 @@
  #include <asm/arch/kw88f6281.h>
  #elif defined (CONFIG_KW88F6192)
  #include <asm/arch/kw88f6192.h>
+#elif defined(CONFIG_KW88F6182)
+#include <asm/arch/kw88f6182.h>
  #else
  #error "SOC Name not defined"
  #endif /* CONFIG_KW88F6281 */
arch/arm/include/asm/arch-kirkwood/cpu.h +2 -0
index 97daa40..e7b6448 100644
@@ -151,5 +151,7 @@ int kw_config_mpp(unsigned int mpp0_7, unsigned int mpp8_15,
  		unsigned int mpp32_39, unsigned int mpp40_47,
  		unsigned int mpp48_55);
  unsigned int kw_winctrl_calcsize(unsigned int sizeval);
+void kirkwood_pcie_id(u32 *dev, u32 *rev);
+char *kirkwood_id(void);
  #endif /* __ASSEMBLY__ */
  #endif /* _KWCPU_H */
arch/arm/include/asm/arch-kirkwood/kirkwood.h +24 -0
index bc207f5..489517f 100644
@@ -39,6 +39,7 @@
  #define KW_EGIGA0_BASE			(KW_REGISTER(0x72000))
  #define KW_EGIGA1_BASE			(KW_REGISTER(0x76000))
  #define KW_SATA_BASE			(KW_REGISTER(0x80000))
+#define KW_SDIO_BASE			(KW_REGISTER(0x90000))
 
  /* Kirkwood Sata controller has two ports */
  #define KW_SATA_PORT0_OFFSET		0x2000
@@ -61,10 +62,33 @@
  #define MVCPU_WIN_ENABLE	KWCPU_WIN_ENABLE
  #define MVCPU_WIN_DISABLE	KWCPU_WIN_DISABLE
 
+/*
+ * Supported devices and revisions.
+ */
+#define MV88F6281_DEV_ID	0x6281
+#define MV88F6281_REV_Z0	0
+#define MV88F6281_REV_A0	2
+#define MV88F6281_REV_A1	3
+
+#define MV88F6192_DEV_ID	0x6192
+#define MV88F6192_REV_Z0	0
+#define MV88F6192_REV_A0	2
+#define MV88F6192_REV_A1	3
+
+#define MV88F6180_DEV_ID	0x6180
+#define MV88F6180_REV_A0	2
+#define MV88F6180_REV_A1	3
+
+#define MV88F6282_DEV_ID	0x6282
+#define MV88F6282_REV_A0	0
+#define MV88F6282_REV_A1	1
+
  #if defined (CONFIG_KW88F6281)
  #include <asm/arch/kw88f6281.h>
  #elif defined (CONFIG_KW88F6192)
  #include <asm/arch/kw88f6192.h>
+#elif defined(CONFIG_KW88F6182)
+#include <asm/arch/kw88f6182.h>
  #else
  #error "SOC Name not defined"
  #endif /* CONFIG_KW88F6281 */
arch/arm/include/asm/arch-kirkwood/kw88f6282.h new file +10 -0
new file mode 100644
index 0000000..5310da2
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <[email protected]>
+ *
+ * Header file for Feroceon CPU core 88FR131 Based KW88F6281 SOC.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *

arch/arm/include/asm/arch-kirkwood/kw88f6282.h line 20

Quoted 10 lines
arch/arm/include/asm/arch-kirkwood/kw88f6282.h new file +10 -0
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */

Again, please use the SPDX license identifier as done in all U-Boot sources now. This is mandatory!

BTW: You seem to be adding a new Kirkwood SoC version with this MMC patch. This really is not MMC related and should be split into a separate patch.

Thanks,
Stefan

author
#2 lore raw

PATCH v4 1/1 ARM: kirkwood: add mvsdio driver

Hi Stefan,

Quoted 3 lines · Stefan Roese

Hi Gerald,

Thanks. But still some more comments below.

Thanks for the review.

Just sent a new version of the patch.

Quoted 3 lines

I still don't see why this function is needed for the MMC driver. It seems to only be used from a debug() output. I suggest to remove it from this patch to not touch the general kirkwood stuff.

Also this MMC driver should be able to support multiple Marvells SoC's, right? So calling some "kirkwood" functions doesn't seem to be generic.

Agree, cleaned as requested.

Quoted 1 line

Again, please use the SPDX license identifier as done in all U-Boot sources now. This is mandatory!

Oops...

Quoted 1 line

BTW: You seem to be adding a new Kirkwood SoC version with this MMC patch. This really is not MMC related and should be split into a separate patch.

Will do this.

Enjoy,

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 538 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140725/d7027389/attachment.pgp>

#3 lore raw

PATCH v4 1/1 ARM: kirkwood: add mvsdio driver

Hi Gerald,

Quoted 10 lines · drEagle

Hi Stefan,

Quoted 3 lines · Stefan Roese

Hi Gerald,

Thanks. But still some more comments below.

Thanks for the review.

Just sent a new version of the patch.

Great. I still have a few comments though. Sorry for not pointing out earlier. I'll send a separate mail for this.

Thanks,
Stefan