Platform: Add GPIO platform service for Musca-S1

On Musca-S1 GPIO is accessible only from the secure world
so a secure service is added for this platform to make it
accessible from the non-secure code as well.

Change-Id: I122c8fda72461bb9c7b20abc640183f552249766
Signed-off-by: Gabor Abonyi <gabor.abonyi@arm.com>
diff --git a/platform/ext/musca_s1.cmake b/platform/ext/musca_s1.cmake
index c5c476d..f2c8b90 100644
--- a/platform/ext/musca_s1.cmake
+++ b/platform/ext/musca_s1.cmake
@@ -59,6 +59,10 @@
 embedded_include_directories(PATH "${PLATFORM_DIR}/../include" ABSOLUTE)
 
 # Gather all source files we need.
+if (TFM_PARTITION_PLATFORM)
+    list(APPEND ALL_SRC_C_NS "${PLATFORM_DIR}/target/musca_s1/services/src/tfm_ioctl_ns_api.c")
+endif()
+
 if (NOT DEFINED BUILD_CMSIS_CORE)
     message(FATAL_ERROR "Configuration variable BUILD_CMSIS_CORE (true|false) is undefined!")
 elseif (BUILD_CMSIS_CORE)
@@ -89,8 +93,9 @@
     message(FATAL_ERROR "Configuration variable BUILD_NATIVE_DRIVERS (true|false) is undefined!")
 elseif (BUILD_NATIVE_DRIVERS)
     list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_s1/Native_Driver/uart_pl011_drv.c")
-    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_s1/Native_Driver/mpc_sie200_drv.c")
     list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_s1/Native_Driver/ppc_sse200_drv.c")
+    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_s1/Native_Driver/gpio_cmsdk_drv.c")
+    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_s1/Native_Driver/mpc_sie200_drv.c")
 endif()
 
 if (NOT DEFINED BUILD_TIME)
@@ -127,6 +132,7 @@
     list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_s1/Native_Driver/mpu_armv8m_drv.c")
     if (TFM_PARTITION_PLATFORM)
         list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_s1/services/src/tfm_platform_system.c")
+        list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_s1/services/src/tfm_ioctl_s_api.c")
     endif()
     list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/common/tfm_platform.c")
     embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
diff --git a/platform/ext/target/musca_s1/Device/Config/device_cfg.h b/platform/ext/target/musca_s1/Device/Config/device_cfg.h
index 94cefc0..8e296f9 100644
--- a/platform/ext/target/musca_s1/Device/Config/device_cfg.h
+++ b/platform/ext/target/musca_s1/Device/Config/device_cfg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,9 @@
  * This is a default device configuration file with all peripherals enabled.
  */
 
+/* ARM GPIO */
+#define GPIO0_CMSDK_S
+
 /* ARM Memory Protection Controller (MPC) SIE 200 */
 #define MPC_ISRAM0_S
 #define MPC_ISRAM1_S
diff --git a/platform/ext/target/musca_s1/Device/Include/device_definition.h b/platform/ext/target/musca_s1/Device/Include/device_definition.h
index 30b624d..5484672 100644
--- a/platform/ext/target/musca_s1/Device/Include/device_definition.h
+++ b/platform/ext/target/musca_s1/Device/Include/device_definition.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -39,10 +39,6 @@
 #include "gpio_cmsdk_drv.h"
 extern struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_S;
 #endif
-#ifdef GPIO0_CMSDK_NS
-#include "gpio_cmsdk_drv.h"
-extern struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_NS;
-#endif
 
 /* ARM MPC SIE 200 driver structures */
 #ifdef MPC_ISRAM0_S
diff --git a/platform/ext/target/musca_s1/Device/Source/device_definition.c b/platform/ext/target/musca_s1/Device/Source/device_definition.c
index d6031d8..8a47e2f 100644
--- a/platform/ext/target/musca_s1/Device/Source/device_definition.c
+++ b/platform/ext/target/musca_s1/Device/Source/device_definition.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,11 +35,6 @@
     .base = MUSCA_S1_GPIO_S_BASE};
 struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_S = {&(GPIO0_CMSDK_DEV_CFG_S)};
 #endif
-#ifdef GPIO0_CMSDK_NS
-static const struct gpio_cmsdk_dev_cfg_t GPIO0_CMSDK_DEV_CFG_NS = {
-    .base = MUSCA_S1_GPIO_NS_BASE};
-struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_NS = {&(GPIO0_CMSDK_DEV_CFG_NS)};
-#endif
 
 /* ARM PPC SSE 200 driver structures */
 #ifdef AHB_PPC0_S
diff --git a/platform/ext/target/musca_s1/Native_Driver/gpio_cmsdk_drv.c b/platform/ext/target/musca_s1/Native_Driver/gpio_cmsdk_drv.c
new file mode 100644
index 0000000..7026069
--- /dev/null
+++ b/platform/ext/target/musca_s1/Native_Driver/gpio_cmsdk_drv.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2016-2018 Arm Limited
+ *
+ * Licensed 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.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "gpio_cmsdk_drv.h"
+
+/* GPIO register map structure */
+struct gpio_cmsdk_reg_map_t {
+    volatile uint32_t  data;           /* Offset: 0x000 (R/W) Data register */
+    volatile uint32_t  dataout;        /* Offset: 0x004 (R/W) Data output
+                                        *                     latch register */
+    volatile uint32_t  reserved0[2];
+    volatile uint32_t  outenableset;   /* Offset: 0x010 (R/W) Output enable
+                                        *                     set register */
+    volatile uint32_t  outenableclr;   /* Offset: 0x014 (R/W) Output enable
+                                        *                     clear register */
+    volatile uint32_t  altfuncset;     /* Offset: 0x018 (R/W) Alternate function
+                                        *                     set register */
+    volatile uint32_t  altfuncclr;     /* Offset: 0x01C (R/W) Alternate function
+                                        *                     clear register */
+    volatile uint32_t  intenset;       /* Offset: 0x020 (R/W) Interrupt enable
+                                        *                     set register */
+    volatile uint32_t  intenclr;       /* Offset: 0x024 (R/W) Interrupt enable
+                                        *                     clear register */
+    volatile uint32_t  inttypeset;     /* Offset: 0x028 (R/W) Interrupt type
+                                        *                     set register */
+    volatile uint32_t  inttypeclr;     /* Offset: 0x02C (R/W) Interrupt type
+                                        *                     clear register */
+    volatile uint32_t  intpolset;      /* Offset: 0x030 (R/W) Interrupt polarity
+                                        *                     set register */
+    volatile uint32_t  intpolclr;      /* Offset: 0x034 (R/W) Interrupt polarity
+                                        *                     clear register */
+    union {
+        volatile uint32_t  intstatus;  /* Offset: 0x038 (R/ ) Interrupt status
+                                        *                     register */
+        volatile uint32_t  intclear;   /* Offset: 0x038 ( /W) Interrupt clear
+                                        *                     register */
+    }intreg;
+    volatile uint32_t reserved1[997];
+    volatile uint32_t pid4;            /* Peripheral ID Register 4 */
+    volatile uint32_t pid0;            /* Peripheral ID Register 0 */
+    volatile uint32_t pid1;            /* Peripheral ID Register 1 */
+    volatile uint32_t pid2;            /* Peripheral ID Register 2 */
+    volatile uint32_t pid3;            /* Peripheral ID Register 3 */
+    volatile uint32_t cid0;            /* Component ID Register 0 */
+    volatile uint32_t cid1;            /* Component ID Register 1 */
+    volatile uint32_t cid2;            /* Component ID Register 2 */
+    volatile uint32_t cid4;            /* Component ID Register 3 */
+};
+
+void gpio_cmsdk_init(struct gpio_cmsdk_dev_t* dev)
+{
+    /* Nothing to init on the GPIO device */
+}
+
+/**
+ * \brief Configures port.
+ *
+ * \param[in] dev             GPIO device to initalize \ref gpio_cmsdk_dev_t
+ * \param[in] pin_mask        Pin mask for port access
+ * \param[in] direction       Input or output \ref gpio_cmsdk_direction_t
+ * \param[in] altfunc_flags   Alternate function \ref gpio_cmsdk_altfunc_t
+ *
+ */
+static void set_port_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                            enum gpio_cmsdk_direction_t direction,
+                            enum gpio_cmsdk_altfunc_t altfunc_flags)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                            (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(direction == GPIO_CMSDK_INPUT) {
+        p_gpio_port->outenableclr = pin_mask;
+    } else {
+        p_gpio_port->outenableset = pin_mask;
+    }
+
+    if (altfunc_flags == GPIO_CMSDK_MAIN_FUNC) {
+        p_gpio_port->altfuncclr = pin_mask;
+    } else {
+        p_gpio_port->altfuncset = pin_mask;
+    }
+
+    return;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_pin_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num,
+                    enum gpio_cmsdk_direction_t direction,
+                    enum gpio_cmsdk_altfunc_t altfunc_flags)
+{
+    uint32_t pin_mask = (1UL << pin_num);
+
+    if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    set_port_config(dev, pin_mask, direction, altfunc_flags);
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_port_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                     enum gpio_cmsdk_direction_t direction,
+                     enum gpio_cmsdk_altfunc_t altfunc_flags)
+{
+    if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    set_port_config(dev, pin_mask, direction, altfunc_flags);
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+void gpio_cmsdk_config_irq(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                         enum gpio_cmsdk_irq_type_t irq_type,
+                         enum gpio_cmsdk_irq_polarity_t irq_pol)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    /* Interrupt type: EDGE = 1 - LEVEL = 0 */
+    if(irq_type == GPIO_CMSDK_IRQ_EDGE) {
+        p_gpio_port->inttypeset = pin_mask;
+    } else if(irq_type == GPIO_CMSDK_IRQ_LEVEL) {
+        p_gpio_port->inttypeclr = pin_mask;
+    }
+
+    /* Interrupt polarity */
+    if(irq_pol == GPIO_CMSDK_IRQ_LOW_OR_FALLING_EDGE) {
+        p_gpio_port->intpolclr = pin_mask;
+    } else if(irq_pol == GPIO_CMSDK_IRQ_HIGH_OR_RISING_EDGE) {
+        p_gpio_port->intpolset = pin_mask;
+    }
+}
+
+enum gpio_cmsdk_error_t gpio_cmsdk_pin_write(struct gpio_cmsdk_dev_t* dev,
+                                         uint32_t pin_num,
+                                         uint32_t value)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    /* GPIO data output register is a read-modify-write register,
+     * so before writing a value on a GPIO pin it is required to disable
+     * the interrupts to prevent concurrency problems.
+     */
+    if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+    if(value) {
+        /* Sets the pin */
+        p_gpio_port->dataout |= (1UL << pin_num);
+    } else {
+        /* Clears the pin */
+        p_gpio_port->dataout &= ~(1UL << pin_num);
+    }
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t gpio_cmsdk_port_write(struct gpio_cmsdk_dev_t* dev,
+                                          uint32_t pin_mask,
+                                          uint32_t value)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    /* GPIO data output register is a read-modify-write register,
+     * so before writing a value on a GPIO pin it is required to disable
+     * the interrupts to prevent concurrency problems.
+     */
+    if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    /* Clear all bits defined in the mask,
+     * and set selected bits from value parameter.
+     */
+    p_gpio_port->dataout =
+                    ((~pin_mask & p_gpio_port->dataout) | (pin_mask  & value));
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_pin_read(struct gpio_cmsdk_dev_t* dev,
+                                    uint32_t pin_num,
+                                    uint32_t *data)
+{
+    uint32_t value;
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    value = p_gpio_port->data;
+
+    *data = (value >> pin_num) & 1UL;
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_port_read(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                   uint32_t *data)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    *data = p_gpio_port->data & pin_mask;
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_set_pin_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num,
+                         enum gpio_cmsdk_irq_status_t status)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    if(status == GPIO_CMSDK_IRQ_ENABLE) {
+        p_gpio_port->intenset = (1UL << pin_num);
+    } else {
+        p_gpio_port->intenclr = (1UL << pin_num);
+    }
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_set_port_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                          enum gpio_cmsdk_irq_status_t status)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    if(status == GPIO_CMSDK_IRQ_ENABLE) {
+        p_gpio_port->intenset = pin_mask;
+    } else {
+        p_gpio_port->intenclr = pin_mask;
+    }
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_get_pin_irq_status(struct gpio_cmsdk_dev_t* dev,
+                            uint32_t pin_num, uint32_t* status)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    *status = ((p_gpio_port->intreg.intstatus >> pin_num) & 1UL);
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+enum gpio_cmsdk_error_t
+gpio_cmsdk_get_port_irq_status(struct gpio_cmsdk_dev_t* dev,
+                             uint32_t pin_mask, uint32_t* status)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    *status = (p_gpio_port->intreg.intstatus & pin_mask);
+
+    return GPIO_CMSDK_ERR_NONE;
+}
+
+
+enum gpio_cmsdk_error_t gpio_cmsdk_clear_irq(struct gpio_cmsdk_dev_t* dev,
+                                         uint8_t pin_num)
+{
+    struct gpio_cmsdk_reg_map_t* p_gpio_port =
+                                (struct gpio_cmsdk_reg_map_t*)dev->cfg->base;
+
+    if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) {
+        return GPIO_CMSDK_ERR_INVALID_ARG;
+    }
+
+    p_gpio_port->intreg.intclear = (1UL << pin_num);
+
+    return GPIO_CMSDK_ERR_NONE;
+}
diff --git a/platform/ext/target/musca_s1/Native_Driver/gpio_cmsdk_drv.h b/platform/ext/target/musca_s1/Native_Driver/gpio_cmsdk_drv.h
new file mode 100644
index 0000000..1df0f5f
--- /dev/null
+++ b/platform/ext/target/musca_s1/Native_Driver/gpio_cmsdk_drv.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2016-2020 Arm Limited
+ *
+ * Licensed 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.
+ */
+
+/**
+ * \file gpio_cmsdk_drv.h
+ * \brief Generic driver for ARM GPIO.
+ */
+
+#ifndef __GPIO_CMSDK_DRV_H__
+#define __GPIO_CMSDK_DRV_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GPIO_CMSDK_MAX_PIN_NUM      16U
+#define GPIO_CMSDK_MAX_PORT_MASK    ((1U << GPIO_CMSDK_MAX_PIN_NUM) - 1U)
+
+/* GPIO enumeration types */
+enum gpio_cmsdk_direction_t {
+    GPIO_CMSDK_INPUT = 0,      /*!< GPIO is input */
+    GPIO_CMSDK_OUTPUT          /*!< GPIO is output */
+};
+
+enum gpio_cmsdk_altfunc_t {
+    GPIO_CMSDK_MAIN_FUNC = 0,  /*!< Alternate function is not enabled */
+    GPIO_CMSDK_ALT_FUNC        /*!< Alternate function is enabled */
+};
+
+enum gpio_cmsdk_irq_status_t {
+    GPIO_CMSDK_IRQ_DISABLE = 0,  /*!< Disable interruptions */
+    GPIO_CMSDK_IRQ_ENABLE        /*!< Enable interruptions */
+};
+
+enum gpio_cmsdk_irq_type_t {
+    GPIO_CMSDK_IRQ_LEVEL = 0,  /*!< Level Interrupt */
+    GPIO_CMSDK_IRQ_EDGE        /*!< Edge Interrupt */
+};
+
+enum gpio_cmsdk_irq_polarity_t {
+    GPIO_CMSDK_IRQ_LOW_OR_FALLING_EDGE = 0,  /*!< Interrupt active low or
+                                                  falling edge */
+    GPIO_CMSDK_IRQ_HIGH_OR_RISING_EDGE       /*!< Interrupt active high or
+                                                  rising edge */
+};
+
+enum gpio_cmsdk_error_t {
+    GPIO_CMSDK_ERR_NONE = 0,      /*!< No error */
+    GPIO_CMSDK_ERR_INVALID_ARG,   /*!< Error invalid input argument */
+    GPIO_CMSDK_ALTFUNC_EERROR,    /*!< Alternate function returned error */
+};
+
+/* CMSDK GPIO device configuration structure */
+struct gpio_cmsdk_dev_cfg_t {
+    const uint32_t base;     /*!< GPIO base address */
+};
+
+/* CMSDK GPIO device structure */
+struct gpio_cmsdk_dev_t {
+    const struct gpio_cmsdk_dev_cfg_t* const cfg;  /*!< GPIO configuration */
+};
+
+/**
+ * \brief Initializes GPIO port.
+ *
+ * \param[in] dev  GPIO device to initalize \ref gpio_cmsdk_dev_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+void gpio_cmsdk_init(struct gpio_cmsdk_dev_t* dev);
+
+/**
+ * \brief Configures pin.
+ *
+ * \param[in] dev             GPIO device to configure \ref gpio_cmsdk_dev_t
+ * \param[in] pin_num         Pin number for pin access
+ * \param[in] direction       Input or output \ref gpio_cmsdk_direction_t
+ * \param[in] altfunc_flags   Alternate function \ref gpio_cmsdk_altfunc_t
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_flags_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_pin_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num,
+                    enum gpio_cmsdk_direction_t direction,
+                    enum gpio_cmsdk_altfunc_t altfunc_flags);
+
+/**
+ * \brief Configures port.
+ *
+ * \param[in] dev             GPIO device to configure \ref gpio_cmsdk_dev_t
+ * \param[in] pin_mask        Bitmask of the selected pins
+ * \param[in] direction       Input or output \ref gpio_cmsdk_direction_t
+ * \param[in] altfunc_flags   Alternate function \ref gpio_cmsdk_altfunc_t
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_port_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                     enum gpio_cmsdk_direction_t direction,
+                     enum gpio_cmsdk_altfunc_t altfunc_flags);
+
+
+/**
+ * \brief Configures interrupt type
+ *
+ * \param[in] dev         GPIO device to initalize \ref gpio_cmsdk_dev_t
+ * \param[in] pin_mask    Bitmask of the selected pins
+ * \param[in] irq_type    Interrupt type \ref gpio_cmsdk_irq_type_t
+ * \param[in] irq_pol     Interrupt polarity \ref gpio_cmsdk_irq_polarity_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+void gpio_cmsdk_config_irq(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                         enum gpio_cmsdk_irq_type_t irq_type,
+                         enum gpio_cmsdk_irq_polarity_t irq_pol);
+
+/**
+ * \brief  Sets state of the output pin.
+ *
+ * \param[in] dev        GPIO device to use for the pin \ref gpio_cmsdk_dev_t
+ * \param[in] pin_num    Pin number for pin access
+ * \param[in] value      Value(s) to set.
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note GPIO data output register is a read-modify-write register,
+ *       so before writing a value on a GPIO pin it is required to disable
+ *       the interrupts to prevent concurrency problems.
+ */
+enum gpio_cmsdk_error_t gpio_cmsdk_pin_write(struct gpio_cmsdk_dev_t* dev,
+                                         uint32_t pin_num,
+                                         uint32_t value);
+
+/**
+ * \brief  Sets state of the output port.
+ *
+ * \param[in] dev        GPIO device to use for the pins \ref gpio_cmsdk_dev_t
+ * \param[in] pin_mask   Bitmask of the selected pins
+ * \param[in] value      Bitmask of pins states to set
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note GPIO data output register is a read-modify-write register,
+ *       so before writing a value on a GPIO pin it is required to disable
+ *       the interrupts to prevent concurrency problems.
+ */
+enum gpio_cmsdk_error_t gpio_cmsdk_port_write(struct gpio_cmsdk_dev_t* dev,
+                                          uint32_t pin_mask,
+                                          uint32_t value);
+
+/**
+ * \brief Reads the pin status.
+ *
+ * \param[in]  dev        GPIO device to use for the pin \ref gpio_cmsdk_dev_t
+ * \param[in]  pin_num    Pin number for pin access
+ * \param[out] data       Bit value read from the IO pin
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_pin_read(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num,
+                    uint32_t *data);
+
+/**
+ * \brief Reads the port status.
+ *
+ * \param[in]  dev        GPIO device to use for the pins \ref gpio_cmsdk_dev_t
+ * \param[in]  pin_mask   Bitmask of the selected pins
+ * \param[out] data       Bit values for the mask read from the IO pin
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_port_read(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                   uint32_t *data);
+
+/**
+ * \brief Enables/disables interrupt for the given pin.
+ *
+ * \param[in] dev        GPIO device to initalize \ref gpio_cmsdk_dev_t
+ * \param[in] pin_num    Pin number to configure
+ * \param[in] status     Interrupt status \ref gpio_cmsdk_irq_status
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_set_pin_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num,
+                         enum gpio_cmsdk_irq_status_t status);
+
+/**
+ * \brief Enables/disables interrupt for the given pins.
+ *
+ * \param[in] dev        GPIO device to use for the pins \ref gpio_cmsdk_dev_t
+ * \param[in] pin_mask   Bitmask of the pins to configure
+ * \param[in] status     Interrupt status \ref gpio_cmsdk_irq_status
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_set_port_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask,
+                          enum gpio_cmsdk_irq_status_t status);
+
+/**
+ * \brief Get interrupt status for the given pin.
+ *
+ * \param[in]  dev       GPIO device to use for the pin \ref gpio_cmsdk_dev_t
+ * \param[in]  pin_num   Pin number for the access
+ * \param[out] status    Interrupt status values. If the access is by pin, then
+ *                       the status will be 0 or 1.
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_get_pin_irq_status(struct gpio_cmsdk_dev_t* dev,
+                            uint32_t pin_num, uint32_t* status);
+
+/**
+ * \brief Get interrupt status for the given port.
+ *
+ * \param[in]  dev        GPIO device to use for the pins \ref gpio_cmsdk_dev_t
+ * \param[in]  pin_mask   Bitmask of the pins to configure
+ * \param[out] status     Interrupt status values. If the access is by pin,
+ *                        then the status will be 0 or 1.
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t
+gpio_cmsdk_get_port_irq_status(struct gpio_cmsdk_dev_t* dev,
+                             uint32_t pin_mask, uint32_t* status);
+
+/**
+ * \brief Clears gpio interrupt.
+ *
+ * \param[in] dev      GPIO device to initalize \ref gpio_cmsdk_dev_t
+ * \param[in] pin_num  Pin number.
+ *
+ * \return Returns error code as specified in \ref gpio_cmsdk_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum gpio_cmsdk_error_t gpio_cmsdk_clear_irq(struct gpio_cmsdk_dev_t* dev,
+                                         uint8_t pin_num);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __GPIO_CMSDK_DRV_H__ */
diff --git a/platform/ext/target/musca_s1/services/include/tfm_ioctl_api.h b/platform/ext/target/musca_s1/services/include/tfm_ioctl_api.h
new file mode 100644
index 0000000..eedeca5
--- /dev/null
+++ b/platform/ext/target/musca_s1/services/include/tfm_ioctl_api.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_IOCTL_API__
+#define __TFM_IOCTL_API__
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "tfm_api.h"
+#include "tfm_platform_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum tfm_platform_ioctl_reqest_types_t {
+    TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+};
+
+/*!
+ * \enum tfm_gpio_service_type_t
+ *
+ * \brief GPIO service types (supported types may vary based on the platform)
+ */
+enum tfm_gpio_service_type_t {
+    TFM_GPIO_SERVICE_TYPE_INIT = 0,          /*!< Init */
+    TFM_GPIO_SERVICE_TYPE_PIN_CONFIG,        /*!< Pin config */
+    TFM_GPIO_SERVICE_TYPE_PIN_WRITE,         /*!< Pin write */
+    TFM_GPIO_SERVICE_TYPE_PIN_READ,          /*!< Pin read */
+    TFM_GPIO_SERVICE_TYPE_PORT_CONFIG,       /*!< Port config */
+    TFM_GPIO_SERVICE_TYPE_PORT_WRITE,        /*!< Port write */
+    TFM_GPIO_SERVICE_TYPE_PORT_READ,         /*!< Port read */
+    TFM_GPIO_SERVICE_TYPE_MAX = INT_MAX      /*!< Max to force enum max size */
+};
+
+/*!
+ * \struct tfm_gpio_service_args_t
+ *
+ * \brief Argument list for each platform GPIO service
+ */
+struct tfm_gpio_service_args_t {
+    enum tfm_gpio_service_type_t type;
+    union {
+        struct gpio_config_args { /*!< TFM_GPIO_SERVICE_TYPE_PIN_CONFIG ||
+                                       TFM_GPIO_SERVICE_TYPE_PORT_CONFIG  */
+            uint32_t pin_num_or_mask;
+            uint32_t direction;
+        } gpio_config;
+        struct gpio_write_args { /*!< TFM_GPIO_SERVICE_TYPE_PIN_WRITE ||
+                                      TFM_GPIO_SERVICE_TYPE_PORT_WRITE */
+            uint32_t pin_num_or_mask;
+            uint32_t value;
+        } gpio_write;
+        struct gpio_read_args { /*!< TFM_GPIO_SERVICE_TYPE_PIN_READ ||
+                                     TFM_GPIO_SERVICE_TYPE_PORT_READ */
+            uint32_t pin_num_or_mask;
+        } gpio_read;
+    } u;
+};
+
+/*!
+ * \struct tfm_gpio_service_out_t
+ *
+ * \brief Output list for each GPIO platform service
+ */
+struct tfm_gpio_service_out_t {
+    union {
+        uint32_t result;               /*!< Generic result */
+        struct gpio_read_result { /*!< TFM_GPIO_SERVICE_TYPE_PIN_READ ||
+                                       TFM_GPIO_SERVICE_TYPE_PORT_READ */
+            uint32_t result;
+            uint32_t data;
+        } gpio_read_result;
+    } u;
+};
+
+/*!
+ * \brief Initializes GPIO module
+ *
+ * \param[out] result       Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t tfm_platform_gpio_init(uint32_t *result);
+
+/*!
+ * \brief Configures a GPIO pin as input or output
+ *
+ * \param[in]  pin_num       Pin number of the selected pin
+ * \param[in]  direction     Direction of the pin: 0 for input, 1 for output
+ * \param[out] result        Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_config(uint32_t pin_num, uint32_t direction,
+                             uint32_t *result);
+
+/*!
+ * \brief Sets state of a selected GPIO pin
+ *
+ * \param[in]  pin_num  Pin number of the selected pin
+ * \param[in]  value    Value to set for the pin
+ * \param[out] result   Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_write(uint32_t pin_num, uint32_t value, uint32_t *result);
+
+/*!
+ * \brief Reads state of a selected GPIO pin
+ *
+ * \param[in]     pin_num  Pin number of the selected pin
+ * \param[in,out] data     Bit value read from the IO pin
+ * \param[out]    result   Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_read(uint32_t pin_num, uint32_t *data, uint32_t *result);
+
+/*!
+ * \brief Configures GPIO pins as input or output
+ *
+ * \param[in]  pin_mask      Pin mask of the selected pins
+ * \param[in]  direction     Direction of the pin: 0 for input, 1 for output
+ * \param[out] result        Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_gpio_port_config(uint32_t pin_mask, uint32_t direction,
+                              uint32_t *result);
+
+/*!
+ * \brief Sets state of a selected GPIO pins
+ *
+ * \param[in]  pin_mask  Pin mask of the selected pins
+ * \param[in]  value     Value mask to set for the pins
+ * \param[out] result    Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_gpio_port_write(uint32_t pin_mask, uint32_t value,
+                             uint32_t *result);
+
+/*!
+ * \brief Reads state of a selected GPIO pins
+ *
+ * \param[in]     pin_mask Pin mask of the selected pins
+ * \param[in,out] data     Bit value mask read from the IO pins
+ * \param[out]    result   Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_gpio_port_read(uint32_t pin_mask, uint32_t *data,
+                            uint32_t *result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_IOCTL_API__ */
diff --git a/platform/ext/target/musca_s1/services/src/tfm_ioctl_ns_api.c b/platform/ext/target/musca_s1/services/src/tfm_ioctl_ns_api.c
new file mode 100644
index 0000000..432dc33
--- /dev/null
+++ b/platform/ext/target/musca_s1/services/src/tfm_ioctl_ns_api.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "tfm_platform_api.h"
+#include "services/include/tfm_ioctl_api.h"
+
+enum tfm_platform_err_t tfm_platform_gpio_init(uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_INIT;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_config(uint32_t pin_num, uint32_t direction,
+                             uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PIN_CONFIG;
+    args.u.gpio_config.pin_num_or_mask = pin_num;
+    args.u.gpio_config.direction = direction;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_write(uint32_t pin_num, uint32_t value, uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PIN_WRITE;
+    args.u.gpio_write.pin_num_or_mask = pin_num;
+    args.u.gpio_write.value = value;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_read(uint32_t pin_num, uint32_t *data, uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PIN_READ;
+    args.u.gpio_read.pin_num_or_mask = pin_num;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.gpio_read_result.result;
+    *data = out.u.gpio_read_result.data;
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_gpio_port_config(uint32_t pin_mask, uint32_t direction,
+                             uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PORT_CONFIG;
+    args.u.gpio_config.pin_num_or_mask = pin_mask;
+    args.u.gpio_config.direction = direction;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_gpio_port_write(uint32_t pin_mask, uint32_t value,
+                             uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PORT_WRITE;
+    args.u.gpio_write.pin_num_or_mask = pin_mask;
+    args.u.gpio_write.value = value;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+
+}
+
+enum tfm_platform_err_t
+tfm_platform_gpio_port_read(uint32_t pin_mask, uint32_t *data, uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PORT_READ;
+    args.u.gpio_read.pin_num_or_mask = pin_mask;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.gpio_read_result.result;
+    *data = out.u.gpio_read_result.data;
+
+    return ret;
+}
diff --git a/platform/ext/target/musca_s1/services/src/tfm_ioctl_s_api.c b/platform/ext/target/musca_s1/services/src/tfm_ioctl_s_api.c
new file mode 100644
index 0000000..a53fc16
--- /dev/null
+++ b/platform/ext/target/musca_s1/services/src/tfm_ioctl_s_api.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "tfm_platform_api.h"
+#include "services/include/tfm_ioctl_api.h"
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t tfm_platform_gpio_init(uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_INIT;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_config(uint32_t pin_num, uint32_t direction,
+                             uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PIN_CONFIG;
+    args.u.gpio_config.pin_num_or_mask = pin_num;
+    args.u.gpio_config.direction = direction;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_write(uint32_t pin_num, uint32_t value, uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PIN_WRITE;
+    args.u.gpio_write.pin_num_or_mask = pin_num;
+    args.u.gpio_write.value = value;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_gpio_pin_read(uint32_t pin_num, uint32_t *data, uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PIN_READ;
+    args.u.gpio_read.pin_num_or_mask = pin_num;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.gpio_read_result.result;
+    *data = out.u.gpio_read_result.data;
+
+    return ret;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_gpio_port_config(uint32_t pin_mask, uint32_t direction,
+                             uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PORT_CONFIG;
+    args.u.gpio_config.pin_num_or_mask = pin_mask;
+    args.u.gpio_config.direction = direction;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_gpio_port_write(uint32_t pin_mask, uint32_t value,
+                             uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PORT_WRITE;
+    args.u.gpio_write.pin_num_or_mask = pin_mask;
+    args.u.gpio_write.value = value;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.result;
+
+    return ret;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_gpio_port_read(uint32_t pin_mask, uint32_t *data, uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_gpio_service_args_t args;
+    struct tfm_gpio_service_out_t out;
+
+    args.type = TFM_GPIO_SERVICE_TYPE_PORT_READ;
+    args.u.gpio_read.pin_num_or_mask = pin_mask;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)&out;
+    out_vec.len = sizeof(out);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    *result = out.u.gpio_read_result.result;
+    *data = out.u.gpio_read_result.data;
+
+    return ret;
+}
diff --git a/platform/ext/target/musca_s1/services/src/tfm_platform_system.c b/platform/ext/target/musca_s1/services/src/tfm_platform_system.c
index 78d8f38..333fc1e 100644
--- a/platform/ext/target/musca_s1/services/src/tfm_platform_system.c
+++ b/platform/ext/target/musca_s1/services/src/tfm_platform_system.c
@@ -1,12 +1,17 @@
 /*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
  */
 
+#include <stdbool.h>
 #include "platform/include/tfm_platform_system.h"
 #include "platform_description.h"
+#include "target_cfg.h"
+#include "device_definition.h"
+#include "psa/client.h"
+#include "services/include/tfm_ioctl_api.h"
 
 void tfm_platform_hal_system_reset(void)
 {
@@ -14,15 +19,87 @@
     NVIC_SystemReset();
 }
 
+enum tfm_platform_err_t
+tfm_platform_hal_gpio_service(const psa_invec  *in_vec,
+                              const psa_outvec *out_vec)
+{
+    struct tfm_gpio_service_args_t *args;
+    struct tfm_gpio_service_out_t *out;
+    enum gpio_cmsdk_direction_t dir;
+    /* Alternate function is configured through the SCC, this is not used
+     * on Musca-S1, the default value is passed to the driver
+     */
+    enum gpio_cmsdk_altfunc_t altfunc = GPIO_CMSDK_MAIN_FUNC;
+
+    if (in_vec->len != sizeof(struct tfm_gpio_service_args_t) ||
+        out_vec->len != sizeof(struct tfm_gpio_service_out_t)) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args = (struct tfm_gpio_service_args_t *)in_vec->base;
+    out = (struct tfm_gpio_service_out_t *)out_vec->base;
+    switch (args->type) {
+    case TFM_GPIO_SERVICE_TYPE_INIT:
+        gpio_cmsdk_init(&GPIO0_CMSDK_DEV_S);
+        out->u.result = GPIO_CMSDK_ERR_NONE;
+        break;
+    case TFM_GPIO_SERVICE_TYPE_PIN_CONFIG:
+        dir = (enum gpio_cmsdk_direction_t)args->u.gpio_config.direction;
+        out->u.result = gpio_cmsdk_pin_config(
+                                            &GPIO0_CMSDK_DEV_S,
+                                            args->u.gpio_config.pin_num_or_mask,
+                                            dir, altfunc);
+        break;
+    case TFM_GPIO_SERVICE_TYPE_PIN_WRITE:
+        out->u.result = gpio_cmsdk_pin_write(
+                                             &GPIO0_CMSDK_DEV_S,
+                                             args->u.gpio_write.pin_num_or_mask,
+                                             args->u.gpio_write.value);
+        break;
+    case TFM_GPIO_SERVICE_TYPE_PIN_READ:
+        out->u.gpio_read_result.result =
+                          gpio_cmsdk_pin_read(&GPIO0_CMSDK_DEV_S,
+                                              args->u.gpio_read.pin_num_or_mask,
+                                              &out->u.gpio_read_result.data);
+        break;
+    case TFM_GPIO_SERVICE_TYPE_PORT_CONFIG:
+        dir = (enum gpio_cmsdk_direction_t)args->u.gpio_config.direction;
+        out->u.result = gpio_cmsdk_port_config(
+                                            &GPIO0_CMSDK_DEV_S,
+                                            args->u.gpio_config.pin_num_or_mask,
+                                            dir, altfunc);
+        break;
+    case TFM_GPIO_SERVICE_TYPE_PORT_WRITE:
+        out->u.result = gpio_cmsdk_port_write(
+                                             &GPIO0_CMSDK_DEV_S,
+                                             args->u.gpio_write.pin_num_or_mask,
+                                             args->u.gpio_write.value);
+        break;
+    case TFM_GPIO_SERVICE_TYPE_PORT_READ:
+        out->u.gpio_read_result.result =
+                         gpio_cmsdk_port_read(&GPIO0_CMSDK_DEV_S,
+                                              args->u.gpio_read.pin_num_or_mask,
+                                              &out->u.gpio_read_result.data);
+        break;
+    default:
+        out->u.result = GPIO_CMSDK_ERR_INVALID_ARG;
+        break;
+    }
+
+    in_vec++;
+    out_vec++;
+
+    return TFM_PLATFORM_ERR_SUCCESS;
+}
+
 enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
                                                psa_invec  *in_vec,
                                                psa_outvec *out_vec)
 {
-    (void)request;
-    (void)in_vec;
-    (void)out_vec;
-
-    /* Not needed for this platform */
-    return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+    switch (request) {
+    case TFM_PLATFORM_IOCTL_GPIO_SERVICE:
+        return tfm_platform_hal_gpio_service(in_vec, out_vec);
+    default:
+        return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+    }
 }
-