diff --git a/boards/risc-v/litex/arty_a7/Kconfig b/boards/risc-v/litex/arty_a7/Kconfig index cedc8e45a4..61584068d3 100644 --- a/boards/risc-v/litex/arty_a7/Kconfig +++ b/boards/risc-v/litex/arty_a7/Kconfig @@ -5,4 +5,24 @@ if ARCH_BOARD_ARTY_A7 +config LITEX_SDIO_MOUNT + bool "Mount SDIO at startup" + default n + depends on LITEX_SDIO + +config LITEX_SDIO_MOUNT_BLKDEV + string "SDIO block device name" + default "/dev/mmcsd0" + depends on LITEX_SDIO + +config LITEX_SDIO_MOUNT_MOUNTPOINT + string "SDIO mountpoint" + default "/mnt" + depends on LITEX_SDIO + +config LITEX_SDIO_MOUNT_FSTYPE + string "SDIO file system type" + default "vfat" + depends on LITEX_SDIO + endif diff --git a/boards/risc-v/litex/arty_a7/src/Makefile b/boards/risc-v/litex/arty_a7/src/Makefile index 7b9f5bfbbd..511f8a84c9 100644 --- a/boards/risc-v/litex/arty_a7/src/Makefile +++ b/boards/risc-v/litex/arty_a7/src/Makefile @@ -26,4 +26,12 @@ ifeq ($(CONFIG_BOARDCTL),y) CSRCS += litex_appinit.c endif +ifeq ($(CONFIG_LITEX_SDIO),y) +CSRCS += litex_sdio.c +endif + +ifeq ($(CONFIG_FS_AUTOMOUNTER),y) +CSRCS += litex_automount.c +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/risc-v/litex/arty_a7/src/arty_a7.h b/boards/risc-v/litex/arty_a7/src/arty_a7.h index 00e564bbcd..1eab373aea 100644 --- a/boards/risc-v/litex/arty_a7/src/arty_a7.h +++ b/boards/risc-v/litex/arty_a7/src/arty_a7.h @@ -27,6 +27,121 @@ #include +/**************************************************************************** + * configuration + */ + +#define HAVE_SDMMC 1 +#define HAVE_AUTOMOUNTER 1 + +/**************************************************************************** + * SDIO Configuration + */ + +#define SDIO_MINOR CONFIG_NSH_MMCSDMINOR +#define SDIO_SLOTNO CONFIG_NSH_MMCSDSLOTNO + +/* Can't support MMC/SD if the card interface(s) are not enable */ + +#if !defined(CONFIG_LITEX_SDIO) && !defined(CONFIG_LITEX_SDIO1) +# undef HAVE_SDMMC +#endif + +#if !defined(CONFIG_FS_AUTOMOUNTER) +# undef HAVE_AUTOMOUNTER +#endif + +/**************************************************************************** + * PROC File System Configuration + */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define LITEX_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define LITEX_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_bringup + * + * Description: + * Bring up board features + * + ****************************************************************************/ + int litex_bringup(void); +/**************************************************************************** + * Name: litex_sdio_initialize + * + * Description: + * Initialize SDIO-based MMC/SD card support + * + ****************************************************************************/ + +#ifdef HAVE_SDMMC +int litex_sdio_initialize(void); +#endif + +/**************************************************************************** + * Name: litex_automount_initialize + * + * Description: + * Configure auto-mounters for each enabled MikroBus MMCSD + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef HAVE_AUTOMOUNTER +int litex_automount_initialize(void); +#endif + +/**************************************************************************** + * Name: litex_automount_event + * + * Description: + * The MMCSD card detection logic has detected an insertion or removal + * event. It has already scheduled the MMC/SD block driver operations. + * Now we need to schedule the auto-mount event which will occur with a + * substantial delay to make sure that everything has settle down. + * + * Input Parameters: + * slotno - Identifies the MB slot: MB1_MMCSD_SLOTNO or MB2_MMCSD_SLOTNO. + * inserted - True if the card is inserted in the slot. False otherwise. + * + * Returned Value: + * None + * + * Assumptions: + * Interrupts are disabled. + * + ****************************************************************************/ + +#ifdef HAVE_AUTOMOUNTER +void litex_automount_event(int slotno, bool inserted); +#endif + +/**************************************************************************** + * Name: litex_cardinserted + * + * Description: + * Check if a card is inserted into the selected MMCSD slot + * + ****************************************************************************/ + +#ifdef HAVE_SDMMC +bool litex_cardinserted(int slotno); +#endif + #endif /* __BOARDS_RISCV_LITEX_ARTY_A7_SRC_ARTY_A7_H */ diff --git a/boards/risc-v/litex/arty_a7/src/litex_automount.c b/boards/risc-v/litex/arty_a7/src/litex_automount.c new file mode 100644 index 0000000000..6a4f065841 --- /dev/null +++ b/boards/risc-v/litex/arty_a7/src/litex_automount.c @@ -0,0 +1,336 @@ +/**************************************************************************** + * boards/risc-v/litex/arty_a7/src/litex_automount.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_FS_AUTOMOUNTER_DEBUG) && !defined(CONFIG_DEBUG_FS) +# define CONFIG_DEBUG_FS 1 +#endif + +#include +#include + +#include +#include +#include + +#include "arty_a7.h" + +#ifdef HAVE_AUTOMOUNTER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the changeable state of the automounter */ + +struct litex_automount_state_s +{ + volatile automount_handler_t handler; /* Upper half handler */ + FAR void *arg; /* Handler argument */ + bool enable; /* Fake interrupt enable */ + bool pending; /* Set if there an event while disabled */ +}; + +/* This structure represents the static configuration of an automounter */ + +struct litex_automount_config_s +{ + /* This must be first thing in structure so that we can simply cast from + * struct automount_lower_s to struct litex_automount_config_s + */ + + struct automount_lower_s lower; /* Publicly visible part */ + uint8_t mmcsd; /* MB1_MMCSD_SLOTNO or MB2_MMCSD_SLOTNO */ + FAR struct litex_automount_state_s *state; /* Changeable state */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int litex_attach(FAR const struct automount_lower_s *lower, + automount_handler_t isr, FAR void *arg); +static void litex_enable(FAR const struct automount_lower_s *lower, + bool enable); +static bool litex_inserted(FAR const struct automount_lower_s *lower); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_LITEX_SDIO_MOUNT_MOUNTPOINT +static struct litex_automount_state_s g_mb1_mmcsdstate; +static const struct litex_automount_config_s g_mb1_mmcsdconfig = +{ + .lower = + { + .fstype = CONFIG_LITEX_SDIO_MOUNT_FSTYPE, + .blockdev = CONFIG_LITEX_SDIO_MOUNT_BLKDEV, + .mountpoint = CONFIG_LITEX_SDIO_MOUNT_MOUNTPOINT, + .ddelay = MSEC2TICK( + 100), + .udelay = MSEC2TICK( + 100), + .attach = litex_attach, + .enable = litex_enable, + .inserted = litex_inserted + }, + .mmcsd = SDIO_SLOTNO, + .state = &g_mb1_mmcsdstate +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_attach + * + * Description: + * Attach a new MMCSD event handler + * + * Input Parameters: + * lower - An instance of the auto-mounter lower half state structure + * isr - The new event handler to be attach + * arg - Client data to be provided when the event handler is invoked. + * + * Returned Value: + * Always returns OK + * + ****************************************************************************/ + +static int litex_attach(FAR const struct automount_lower_s *lower, + automount_handler_t isr, FAR void *arg) +{ + FAR const struct litex_automount_config_s *config; + FAR struct litex_automount_state_s *state; + + /* Recover references to our structure */ + + config = (FAR struct litex_automount_config_s *)lower; + DEBUGASSERT(config && config->state); + + state = config->state; + + /* Save the new handler info (clearing the handler first to eliminate race + * conditions). + */ + + state->handler = NULL; + state->pending = false; + state->arg = arg; + state->handler = isr; + return OK; +} + +/**************************************************************************** + * Name: litex_enable + * + * Description: + * Enable card insertion/removal event detection + * + * Input Parameters: + * lower - An instance of the auto-mounter lower half state structure + * enable - True: enable event detection; False: disable + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void litex_enable(FAR const struct automount_lower_s *lower, + bool enable) +{ + FAR const struct litex_automount_config_s *config; + FAR struct litex_automount_state_s *state; + irqstate_t flags; + + /* Recover references to our structure */ + + config = (FAR struct litex_automount_config_s *)lower; + DEBUGASSERT(config && config->state); + + state = config->state; + + /* Save the fake enable setting */ + + flags = enter_critical_section(); + state->enable = enable; + + /* Did an interrupt occur while interrupts were disabled? */ + + if (enable && state->pending) + { + /* Yes.. perform the fake interrupt if the interrupt is attached */ + + if (state->handler) + { + bool inserted = litex_cardinserted(config->mmcsd); + state->handler(&config->lower, state->arg, inserted); + } + + state->pending = false; + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: litex_inserted + * + * Description: + * Check if a card is inserted into the slot. + * + * Input Parameters: + * lower - An instance of the auto-mounter lower half state structure + * + * Returned Value: + * True if the card is inserted; False otherwise + * + ****************************************************************************/ + +static bool litex_inserted(FAR const struct automount_lower_s *lower) +{ + FAR const struct litex_automount_config_s *config; + + config = (FAR struct litex_automount_config_s *)lower; + DEBUGASSERT(config && config->state); + + return litex_cardinserted(config->mmcsd); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_automount_initialize + * + * Description: + * Configure auto-mounters for each enabled MMCSD MikroBus slot + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +int litex_automount_initialize(void) +{ + FAR void *handle; + + finfo("Initializing automounter(s)\n"); + +#ifdef CONFIG_LITEX_SDIO_MOUNT_MOUNTPOINT + /* Initialize the MB1 MMCSD auto-mounter */ + + handle = automount_initialize(&g_mb1_mmcsdconfig.lower); + if (!handle) + { + ferr("ERROR: Failed to initialize auto-mounter for MB1 MMCSD\n"); + return ERROR; + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: litex_automount_event + * + * Description: + * The HSMCI card detection logic has detected an insertion or removal + * event. It has already scheduled the MMC/SD block driver operations. + * Now we need to schedule the auto-mount event which will occur with a + * substantial delay to make sure that everything has settle down. + * + * Input Parameters: + * slotno - Identifies the MB slot: MB1_MMCSD_SLOTNO or MB2_MMCSD_SLOTNO. + * There is a terminology problem here: Each HSMCI supports two slots, + * slot A and slot B. Only slot A is used. So this is not a really a + * slot, but an HSCMI peripheral number. + * inserted - True if the card is inserted in the slot. False otherwise. + * + * Returned Value: + * None + * + * Assumptions: + * Interrupts are disabled. + * + ****************************************************************************/ + +void litex_automount_event(int slotno, bool inserted) +{ + FAR const struct litex_automount_config_s *config; + FAR struct litex_automount_state_s *state; + +#ifdef CONFIG_LITEX_SDIO_MOUNT_MOUNTPOINT + /* Is this a change in the MB1 MMCSD slot insertion state? */ + + if (slotno == SDIO_SLOTNO) + { + /* Yes.. Select the MB1 MMCSD automounter */ + + config = &g_mb1_mmcsdconfig; + state = &g_mb1_mmcsdstate; + } + else +#endif + { + ferr("ERROR: Unsupported MMCSD%d\n", slotno); + return; + } + + /* Is the auto-mounter interrupt attached? */ + + if (state->handler) + { + /* Yes.. Have we been asked to hold off interrupts? */ + + if (!state->enable) + { + /* Yes.. just remember that there is a pending interrupt. We will + * deliver the interrupt when interrupts are "re-enabled." + */ + + state->pending = true; + } + else + { + /* No.. forward the event to the handler */ + + state->handler(&config->lower, state->arg, inserted); + } + } +} + +#endif /* HAVE_AUTOMOUNTER */ diff --git a/boards/risc-v/litex/arty_a7/src/litex_bringup.c b/boards/risc-v/litex/arty_a7/src/litex_bringup.c index a1f8b1ab94..826d2eb4f2 100644 --- a/boards/risc-v/litex/arty_a7/src/litex_bringup.c +++ b/boards/risc-v/litex/arty_a7/src/litex_bringup.c @@ -31,9 +31,9 @@ #include #include -#include #include "litex.h" +#include "arty_a7.h" /**************************************************************************** * Public Functions @@ -50,12 +50,57 @@ int litex_bringup(void) #ifdef CONFIG_FS_PROCFS /* Mount the procfs file system */ - ret = nx_mount(NULL, "/proc", "procfs", 0, NULL); + ret = nx_mount(NULL, LITEX_PROCFS_MOUNTPOINT, "procfs", 0, NULL); if (ret < 0) { - serr("ERROR: Failed to mount procfs at %s: %d\n", "/proc", ret); + syslog(LOG_ERR, "failed to mount procfs at %s %d\n", + LITEX_PROCFS_MOUNTPOINT, ret); } #endif +#ifdef CONFIG_FS_AUTOMOUNTER + /* Configure uSD automounter */ + + ret = litex_automount_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: litex_automount_initialize() failed: %d\n", + ret); + } +#endif + +#ifdef CONFIG_LITEX_SDIO + /* Initialize the SDIO block driver */ + + ret = litex_sdio_initialize(); + if (ret != OK) + { + syslog(LOG_ERR, "litex_sdio_initialize() failed %d\n", ret); + return ret; + } + + /* If automount not configured, force a mount point. + * Assumes the card is always present. + */ + +#ifndef CONFIG_FS_AUTOMOUNTER +#ifdef CONFIG_LITEX_SDIO_MOUNT + /* Mount the volume on SDMMC0 */ + + ret = nx_mount(CONFIG_LITEX_SDIO_MOUNT_BLKDEV, + CONFIG_LITEX_SDIO_MOUNT_MOUNTPOINT, + CONFIG_LITEX_SDIO_MOUNT_FSTYPE, + 0, NULL); + + if (ret != OK) + { + syslog(LOG_ERR, "ERROR: Failed to mount %s: %d\n", + CONFIG_LITEX_SDIO_MOUNT_MOUNTPOINT, ret); + } +#endif /* CONFIG_LITEX_SDIO_MOUNT */ +#endif + +#endif /* CONFIG_LITEX_SDIO */ + return ret; } diff --git a/boards/risc-v/litex/arty_a7/src/litex_sdio.c b/boards/risc-v/litex/arty_a7/src/litex_sdio.c new file mode 100644 index 0000000000..1b731e9cce --- /dev/null +++ b/boards/risc-v/litex/arty_a7/src/litex_sdio.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * boards/risc-v/litex/arty_a7/src/litex_sdio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "litex.h" +#include "arty_a7.h" +#include "litex_sdio.h" + +#ifdef HAVE_SDMMC + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_sdio_card_isr_callback + * + * Description: + * Check if a card is inserted into the selected MMCSD slot + * + ****************************************************************************/ + +static void litex_sdio_card_isr_callback(void *arg) +{ + bool cd; + + cd = litex_cardinserted(SDIO_SLOTNO); + finfo("Card detect: %d\n", cd); + sdio_mediachange(arg, cd); + +#ifdef HAVE_AUTOMOUNTER + /* Let the automounter know about the insertion event */ + + litex_automount_event(SDIO_SLOTNO, cd); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: litex_cardinserted + * + * Description: + * Check if a card is inserted into the selected MMCSD slot + * + ****************************************************************************/ + +bool litex_cardinserted(int slotno) +{ + return litex_sdio_get_card_detect(); +} + +/**************************************************************************** + * Name: litex_sdio_initialize + * + * Description: + * Initialize SDIO-based MMC/SD card support + * + ****************************************************************************/ + +int litex_sdio_initialize(void) +{ + int ret = 0; + struct sdio_dev_s *sdio_dev; + + finfo("Initializing SDIO slot %d\n", SDIO_SLOTNO); + sdio_dev = sdio_initialize(SDIO_SLOTNO); + if (sdio_dev == NULL) + { + ferr("ERROR: Failed to initialize SDIO slot %d\n", SDIO_SLOTNO); + return -ENODEV; + } + + finfo("Bind SDIO to the MMC/SD driver, minor=%d\n", SDIO_MINOR); + ret = mmcsd_slotinitialize(SDIO_MINOR, sdio_dev); + if (ret != OK) + { + ferr("ERROR: Failed to bind SDIO to the MMC/SD driver: %d\n", ret); + return ret; + } + + litex_sdio_set_card_isr(sdio_dev, &litex_sdio_card_isr_callback, sdio_dev); + + finfo("Successfully bound SDIO to the MMC/SD driver\n"); + + /* Assume that the SD card is inserted. + * The Arty A7 board doesnt have the CD pin wired. + */ + + sdio_mediachange(sdio_dev, litex_sdio_get_card_detect()); + + return OK; +} + +#endif /* HAVE_SDMMC */