diff --git a/MAINTAINERS b/MAINTAINERS
index 153c3ff4de..3ce78e6896 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1338,6 +1338,12 @@ M: Tomasz Duszynski <tduszynski@marvell.com>
 F: doc/guides/rawdevs/cnxk_bphy.rst
 F: drivers/raw/cnxk_bphy/
 
+Marvell CNXK GPIO
+M: Jakub Palider <jpalider@marvell.com>
+M: Tomasz Duszynski <tduszynski@marvell.com>
+F: doc/guides/rawdevs/cnxk_gpio.rst
+F: drivers/raw/cnxk_gpio/
+
 NTB
 M: Jingjing Wu <jingjing.wu@intel.com>
 M: Junfeng Guo <junfeng.guo@intel.com>
diff --git a/doc/guides/platform/cnxk.rst b/doc/guides/platform/cnxk.rst
index 97e38c868c..3dee725ac5 100644
--- a/doc/guides/platform/cnxk.rst
+++ b/doc/guides/platform/cnxk.rst
@@ -73,6 +73,8 @@ DPDK subsystem.
    +---+-----+--------------------------------------------------------------+
    | 11| BPHY| rte_rawdev                                                   |
    +---+-----+--------------------------------------------------------------+
+   | 12| GPIO| rte_rawdev                                                   |
+   +---+-----+--------------------------------------------------------------+
 
 PF0 is called the administrative / admin function (AF) and has exclusive
 privileges to provision RVU functional block's LFs to each of the PF/VF.
diff --git a/doc/guides/rawdevs/cnxk_gpio.rst b/doc/guides/rawdevs/cnxk_gpio.rst
new file mode 100644
index 0000000000..868302d07f
--- /dev/null
+++ b/doc/guides/rawdevs/cnxk_gpio.rst
@@ -0,0 +1,65 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2021 Marvell.
+
+Marvell CNXK GPIO Driver
+========================
+
+CNXK GPIO PMD configures and manages GPIOs available on the system using
+standard enqueue/dequeue mechanism offered by raw device abstraction. PMD relies
+both on standard sysfs GPIO interface provided by the Linux kernel and GPIO
+kernel driver custom interface allowing one to install userspace interrupt
+handlers.
+
+Features
+--------
+
+Following features are available:
+
+- export/unexport a GPIO
+- read/write specific value from/to exported GPIO
+- set GPIO direction
+- set GPIO edge that triggers interrupt
+- set GPIO active low
+- register interrupt handler for specific GPIO
+
+Requirements
+------------
+
+PMD relies on modified kernel GPIO driver which exposes ``ioctl()`` interface
+for installing interrupt handlers for low latency signal processing.
+
+Driver is shipped with Marvell SDK.
+
+Device Setup
+------------
+
+CNXK GPIO PMD binds to virtual device which gets created by passing
+`--vdev=cnxk_gpio,gpiochip=<number>` command line to EAL. `gpiochip` parameter
+tells PMD which GPIO controller should be used. Available controllers are
+available under `/sys/class/gpio`. For further details on how Linux represents
+GPIOs in userspace please refer to
+`sysfs.txt <https://www.kernel.org/doc/Documentation/gpio/sysfs.txt>`_.
+
+If `gpiochip=<number>` was omitted then first gpiochip from the alphabetically
+sort list of available gpiochips is used.
+
+.. code-block:: console
+
+   $ ls /sys/class/gpio
+   export gpiochip448 unexport
+
+In above scenario only one GPIO controller is present hence
+`--vdev=cnxk_gpio,gpiochip=448` should be passed to EAL.
+
+Before performing actual data transfer one needs to call
+``rte_rawdev_queue_count()`` followed by ``rte_rawdev_queue_conf_get()``. The
+former returns number GPIOs available in the system irrespective of GPIOs
+being controllable or not. Thus it is user responsibility to pick the proper
+ones. The latter call simply returns queue capacity.
+
+Respective queue needs to be configured with ``rte_rawdev_queue_setup()``. This
+call barely exports GPIO to userspace.
+
+To perform actual data transfer use standard ``rte_rawdev_enqueue_buffers()``
+and ``rte_rawdev_dequeue_buffers()`` APIs. Not all messages produce sensible
+responses hence dequeueing is not always necessary.
diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst
index b6cf917443..0c02da6e90 100644
--- a/doc/guides/rawdevs/index.rst
+++ b/doc/guides/rawdevs/index.rst
@@ -12,6 +12,7 @@ application through rawdev API.
     :numbered:
 
     cnxk_bphy
+    cnxk_gpio
     dpaa2_cmdif
     dpaa2_qdma
     ifpga
diff --git a/doc/guides/rel_notes/release_22_03.rst b/doc/guides/rel_notes/release_22_03.rst
index 41923f50e6..714b7c8e5f 100644
--- a/doc/guides/rel_notes/release_22_03.rst
+++ b/doc/guides/rel_notes/release_22_03.rst
@@ -55,6 +55,7 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+<<<<<<< HEAD
 * **Added ability to reuse hugepages in Linux.**
 
   It is possible to reuse files in hugetlbfs to speed up hugepage mapping,
@@ -158,6 +159,15 @@ New Features
   * Called ``rte_ipv4/6_udptcp_cksum_mbuf()`` functions in testpmd csum mode
     to support software UDP/TCP checksum over multiple segments.
 
+* **Added CNXK GPIO PMD.**
+
+  Added a new rawdevice PMD which allows to manage userspace GPIOs and install
+  custom GPIO interrupt handlers which bypass kernel. This is especially useful
+  for applications, that besides providing standard dataplane functionality
+  want to have fast and low latency access to GPIO pin state.
+
+  See the :doc:`../rawdevs/cnxk_gpio` rawdev guide for more details on this
+  driver.
 
 Removed Items
 -------------
diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.c b/drivers/raw/cnxk_gpio/cnxk_gpio.c
new file mode 100644
index 0000000000..61069b2185
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/cnxk_gpio.c
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include <dirent.h>
+#include <string.h>
+
+#include <rte_bus_vdev.h>
+#include <rte_eal.h>
+#include <rte_kvargs.h>
+#include <rte_lcore.h>
+#include <rte_rawdev_pmd.h>
+
+#include <roc_api.h>
+
+#include "cnxk_gpio.h"
+
+#define CNXK_GPIO_BUFSZ 128
+#define CNXK_GPIO_CLASS_PATH "/sys/class/gpio"
+
+static const char *const cnxk_gpio_args[] = {
+#define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
+	CNXK_GPIO_ARG_GPIOCHIP,
+	NULL
+};
+
+static void
+cnxk_gpio_format_name(char *name, size_t len)
+{
+	snprintf(name, len, "cnxk_gpio");
+}
+
+static int
+cnxk_gpio_filter_gpiochip(const struct dirent *dirent)
+{
+	const char *pattern = "gpiochip";
+
+	return !strncmp(dirent->d_name, pattern, strlen(pattern));
+}
+
+static void
+cnxk_gpio_set_defaults(struct cnxk_gpiochip *gpiochip)
+{
+	struct dirent **namelist;
+	int n;
+
+	n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip,
+		    alphasort);
+	if (n < 0 || n == 0)
+		return;
+
+	sscanf(namelist[0]->d_name, "gpiochip%d", &gpiochip->num);
+	while (n--)
+		free(namelist[n]);
+	free(namelist);
+}
+
+static int
+cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
+			     void *extra_args)
+{
+	long val;
+
+	errno = 0;
+	val = strtol(value, NULL, 10);
+	if (errno)
+		return -errno;
+
+	*(int *)extra_args = (int)val;
+
+	return 0;
+}
+
+static int
+cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip,
+		     struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	kvlist = rte_kvargs_parse(devargs->args, cnxk_gpio_args);
+	if (!kvlist)
+		return 0;
+
+	ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_GPIOCHIP);
+	if (ret == 1) {
+		ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_GPIOCHIP,
+					 cnxk_gpio_parse_arg_gpiochip,
+					 &gpiochip->num);
+		if (ret)
+			goto out;
+	}
+
+	ret = 0;
+out:
+	rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+static int
+cnxk_gpio_read_attr(char *attr, char *val)
+{
+	FILE *fp;
+	int ret;
+
+	fp = fopen(attr, "r");
+	if (!fp)
+		return -errno;
+
+	ret = fscanf(fp, "%s", val);
+	if (ret < 0)
+		return -errno;
+	if (ret != 1)
+		return -EIO;
+
+	ret = fclose(fp);
+	if (ret)
+		return -errno;
+
+	return 0;
+}
+
+static int
+cnxk_gpio_read_attr_int(char *attr, int *val)
+{
+	char buf[CNXK_GPIO_BUFSZ];
+	int ret;
+
+	ret = cnxk_gpio_read_attr(attr, buf);
+	if (ret)
+		return ret;
+
+	ret = sscanf(buf, "%d", val);
+	if (ret < 0)
+		return -errno;
+
+	return 0;
+}
+
+static int
+cnxk_gpio_dev_close(struct rte_rawdev *dev)
+{
+	RTE_SET_USED(dev);
+
+	return 0;
+}
+
+static const struct rte_rawdev_ops cnxk_gpio_rawdev_ops = {
+	.dev_close = cnxk_gpio_dev_close,
+};
+
+static int
+cnxk_gpio_probe(struct rte_vdev_device *dev)
+{
+	char name[RTE_RAWDEV_NAME_MAX_LEN];
+	struct cnxk_gpiochip *gpiochip;
+	struct rte_rawdev *rawdev;
+	char buf[CNXK_GPIO_BUFSZ];
+	int ret;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	cnxk_gpio_format_name(name, sizeof(name));
+	rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip),
+					 rte_socket_id());
+	if (!rawdev) {
+		RTE_LOG(ERR, PMD, "failed to allocate %s rawdev", name);
+		return -ENOMEM;
+	}
+
+	rawdev->dev_ops = &cnxk_gpio_rawdev_ops;
+	rawdev->device = &dev->device;
+	rawdev->driver_name = dev->device.name;
+
+	gpiochip = rawdev->dev_private;
+	cnxk_gpio_set_defaults(gpiochip);
+
+	/* defaults may be overwritten by this call */
+	ret = cnxk_gpio_parse_args(gpiochip, dev->device.devargs);
+	if (ret)
+		goto out;
+
+	/* read gpio base */
+	snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH,
+		 gpiochip->num);
+	ret = cnxk_gpio_read_attr_int(buf, &gpiochip->base);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "failed to read %s", buf);
+		goto out;
+	}
+
+	/* read number of available gpios */
+	snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH,
+		 gpiochip->num);
+	ret = cnxk_gpio_read_attr_int(buf, &gpiochip->num_gpios);
+	if (ret) {
+		RTE_LOG(ERR, PMD, "failed to read %s", buf);
+		goto out;
+	}
+
+	gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios,
+				     sizeof(struct cnxk_gpio *), 0);
+	if (!gpiochip->gpios) {
+		RTE_LOG(ERR, PMD, "failed to allocate gpios memory");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	return 0;
+out:
+	rte_rawdev_pmd_release(rawdev);
+
+	return ret;
+}
+
+static int
+cnxk_gpio_remove(struct rte_vdev_device *dev)
+{
+	char name[RTE_RAWDEV_NAME_MAX_LEN];
+	struct cnxk_gpiochip *gpiochip;
+	struct rte_rawdev *rawdev;
+
+	RTE_SET_USED(dev);
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	cnxk_gpio_format_name(name, sizeof(name));
+	rawdev = rte_rawdev_pmd_get_named_dev(name);
+	if (!rawdev)
+		return -ENODEV;
+
+	gpiochip = rawdev->dev_private;
+	rte_free(gpiochip->gpios);
+	rte_rawdev_pmd_release(rawdev);
+
+	return 0;
+}
+
+static struct rte_vdev_driver cnxk_gpio_drv = {
+	.probe = cnxk_gpio_probe,
+	.remove = cnxk_gpio_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(cnxk_gpio, cnxk_gpio_drv);
+RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio, "gpiochip=<int>");
diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.h b/drivers/raw/cnxk_gpio/cnxk_gpio.h
new file mode 100644
index 0000000000..4dae8316ba
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/cnxk_gpio.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#ifndef _CNXK_GPIO_H_
+#define _CNXK_GPIO_H_
+
+struct cnxk_gpiochip;
+
+struct cnxk_gpio {
+	struct cnxk_gpiochip *gpiochip;
+	int num;
+};
+
+struct cnxk_gpiochip {
+	int num;
+	int base;
+	int num_gpios;
+	struct cnxk_gpio **gpios;
+};
+
+#endif /* _CNXK_GPIO_H_ */
diff --git a/drivers/raw/cnxk_gpio/meson.build b/drivers/raw/cnxk_gpio/meson.build
new file mode 100644
index 0000000000..9a7e716c1e
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/meson.build
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(C) 2021 Marvell.
+#
+
+deps += ['bus_vdev', 'common_cnxk', 'rawdev', 'kvargs']
+sources = files(
+        'cnxk_gpio.c',
+)
diff --git a/drivers/raw/cnxk_gpio/version.map b/drivers/raw/cnxk_gpio/version.map
new file mode 100644
index 0000000000..4a76d1d52d
--- /dev/null
+++ b/drivers/raw/cnxk_gpio/version.map
@@ -0,0 +1,3 @@
+DPDK_21 {
+	local: *;
+};
diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build
index 87694a758e..05e7de1bfe 100644
--- a/drivers/raw/meson.build
+++ b/drivers/raw/meson.build
@@ -7,6 +7,7 @@ endif
 
 drivers = [
         'cnxk_bphy',
+        'cnxk_gpio',
         'dpaa2_cmdif',
         'dpaa2_qdma',
         'ifpga',
