diff --git a/drivers/common/cnxk/meson.build b/drivers/common/cnxk/meson.build
index e6e2ad3..1b02178 100644
--- a/drivers/common/cnxk/meson.build
+++ b/drivers/common/cnxk/meson.build
@@ -42,5 +42,6 @@ sources = files('roc_dev.c',
 		'roc_sso.c',
 		'roc_sso_debug.c',
 		'roc_sso_irq.c',
+		'roc_tim.c',
 		'roc_utils.c')
 includes += include_directories('../../bus/pci')
diff --git a/drivers/common/cnxk/roc_api.h b/drivers/common/cnxk/roc_api.h
index b7fc3b7..67f5d13 100644
--- a/drivers/common/cnxk/roc_api.h
+++ b/drivers/common/cnxk/roc_api.h
@@ -91,6 +91,9 @@
 /* SSO */
 #include "roc_sso.h"
 
+/* TIM */
+#include "roc_tim.h"
+
 /* Utils */
 #include "roc_utils.h"
 
diff --git a/drivers/common/cnxk/roc_platform.c b/drivers/common/cnxk/roc_platform.c
index 17822f6..a4b6c88 100644
--- a/drivers/common/cnxk/roc_platform.c
+++ b/drivers/common/cnxk/roc_platform.c
@@ -59,4 +59,5 @@ RTE_LOG_REGISTER(cnxk_logtype_npa, pmd.mempool.cnxk, NOTICE);
 RTE_LOG_REGISTER(cnxk_logtype_nix, pmd.net.cnxk, NOTICE);
 RTE_LOG_REGISTER(cnxk_logtype_npc, pmd.net.cnxk.flow, NOTICE);
 RTE_LOG_REGISTER(cnxk_logtype_sso, pmd.event.cnxk, NOTICE);
+RTE_LOG_REGISTER(cnxk_logtype_tim, pmd.event.cnxk.timer, NOTICE);
 RTE_LOG_REGISTER(cnxk_logtype_tm, pmd.net.cnxk.tm, NOTICE);
diff --git a/drivers/common/cnxk/roc_platform.h b/drivers/common/cnxk/roc_platform.h
index 13636e4..1d5ffb7 100644
--- a/drivers/common/cnxk/roc_platform.h
+++ b/drivers/common/cnxk/roc_platform.h
@@ -138,6 +138,7 @@ extern int cnxk_logtype_npa;
 extern int cnxk_logtype_nix;
 extern int cnxk_logtype_npc;
 extern int cnxk_logtype_sso;
+extern int cnxk_logtype_tim;
 extern int cnxk_logtype_tm;
 
 #define plt_err(fmt, args...)                                                  \
@@ -160,6 +161,7 @@ extern int cnxk_logtype_tm;
 #define plt_nix_dbg(fmt, ...)	plt_dbg(nix, fmt, ##__VA_ARGS__)
 #define plt_npc_dbg(fmt, ...)	plt_dbg(npc, fmt, ##__VA_ARGS__)
 #define plt_sso_dbg(fmt, ...)	plt_dbg(sso, fmt, ##__VA_ARGS__)
+#define plt_tim_dbg(fmt, ...)	plt_dbg(tim, fmt, ##__VA_ARGS__)
 #define plt_tm_dbg(fmt, ...)	plt_dbg(tm, fmt, ##__VA_ARGS__)
 
 #ifdef __cplusplus
diff --git a/drivers/common/cnxk/roc_priv.h b/drivers/common/cnxk/roc_priv.h
index dd9d87a..5e7564c 100644
--- a/drivers/common/cnxk/roc_priv.h
+++ b/drivers/common/cnxk/roc_priv.h
@@ -29,4 +29,7 @@
 /* SSO */
 #include "roc_sso_priv.h"
 
+/* TIM */
+#include "roc_tim_priv.h"
+
 #endif /* _ROC_PRIV_H_ */
diff --git a/drivers/common/cnxk/roc_tim.c b/drivers/common/cnxk/roc_tim.c
new file mode 100644
index 0000000..37faa37
--- /dev/null
+++ b/drivers/common/cnxk/roc_tim.c
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include "roc_api.h"
+#include "roc_priv.h"
+
+static void
+tim_err_desc(int rc)
+{
+	switch (rc) {
+	case TIM_AF_NO_RINGS_LEFT:
+		plt_err("Unable to allocate new TIM ring.");
+		break;
+	case TIM_AF_INVALID_NPA_PF_FUNC:
+		plt_err("Invalid NPA pf func.");
+		break;
+	case TIM_AF_INVALID_SSO_PF_FUNC:
+		plt_err("Invalid SSO pf func.");
+		break;
+	case TIM_AF_RING_STILL_RUNNING:
+		plt_err("Ring busy.");
+		break;
+	case TIM_AF_LF_INVALID:
+		plt_err("Invalid Ring id.");
+		break;
+	case TIM_AF_CSIZE_NOT_ALIGNED:
+		plt_err("Chunk size specified needs to be multiple of 16.");
+		break;
+	case TIM_AF_CSIZE_TOO_SMALL:
+		plt_err("Chunk size too small.");
+		break;
+	case TIM_AF_CSIZE_TOO_BIG:
+		plt_err("Chunk size too big.");
+		break;
+	case TIM_AF_INTERVAL_TOO_SMALL:
+		plt_err("Bucket traversal interval too small.");
+		break;
+	case TIM_AF_INVALID_BIG_ENDIAN_VALUE:
+		plt_err("Invalid Big endian value.");
+		break;
+	case TIM_AF_INVALID_CLOCK_SOURCE:
+		plt_err("Invalid Clock source specified.");
+		break;
+	case TIM_AF_GPIO_CLK_SRC_NOT_ENABLED:
+		plt_err("GPIO clock source not enabled.");
+		break;
+	case TIM_AF_INVALID_BSIZE:
+		plt_err("Invalid bucket size.");
+		break;
+	case TIM_AF_INVALID_ENABLE_PERIODIC:
+		plt_err("Invalid bucket size.");
+		break;
+	case TIM_AF_INVALID_ENABLE_DONTFREE:
+		plt_err("Invalid Don't free value.");
+		break;
+	case TIM_AF_ENA_DONTFRE_NSET_PERIODIC:
+		plt_err("Don't free bit not set when periodic is enabled.");
+		break;
+	case TIM_AF_RING_ALREADY_DISABLED:
+		plt_err("Ring already stopped");
+		break;
+	default:
+		plt_err("Unknown Error.");
+	}
+}
+
+int
+roc_tim_lf_enable(struct roc_tim *roc_tim, uint8_t ring_id, uint64_t *start_tsc,
+		  uint32_t *cur_bkt)
+{
+	struct dev *dev = &roc_sso_to_sso_priv(roc_tim->roc_sso)->dev;
+	struct tim_enable_rsp *rsp;
+	struct tim_ring_req *req;
+	int rc = -ENOSPC;
+
+	req = mbox_alloc_msg_tim_enable_ring(dev->mbox);
+	if (req == NULL)
+		return rc;
+	req->ring = ring_id;
+
+	rc = mbox_process_msg(dev->mbox, (void **)&rsp);
+	if (rc < 0) {
+		tim_err_desc(rc);
+		return rc;
+	}
+
+	if (cur_bkt)
+		*cur_bkt = rsp->currentbucket;
+	if (start_tsc)
+		*start_tsc = rsp->timestarted;
+
+	return 0;
+}
+
+int
+roc_tim_lf_disable(struct roc_tim *roc_tim, uint8_t ring_id)
+{
+	struct dev *dev = &roc_sso_to_sso_priv(roc_tim->roc_sso)->dev;
+	struct tim_ring_req *req;
+	int rc = -ENOSPC;
+
+	req = mbox_alloc_msg_tim_disable_ring(dev->mbox);
+	if (req == NULL)
+		return rc;
+	req->ring = ring_id;
+
+	rc = mbox_process(dev->mbox);
+	if (rc < 0) {
+		tim_err_desc(rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+uintptr_t
+roc_tim_lf_base_get(struct roc_tim *roc_tim, uint8_t ring_id)
+{
+	struct dev *dev = &roc_sso_to_sso_priv(roc_tim->roc_sso)->dev;
+
+	return dev->bar2 + (RVU_BLOCK_ADDR_TIM << 20 | ring_id << 12);
+}
+
+int
+roc_tim_lf_config(struct roc_tim *roc_tim, uint8_t ring_id,
+		  enum roc_tim_clk_src clk_src, uint8_t ena_periodic,
+		  uint8_t ena_dfb, uint32_t bucket_sz, uint32_t chunk_sz,
+		  uint32_t interval)
+{
+	struct dev *dev = &roc_sso_to_sso_priv(roc_tim->roc_sso)->dev;
+	struct tim_config_req *req;
+	int rc = -ENOSPC;
+
+	req = mbox_alloc_msg_tim_config_ring(dev->mbox);
+	if (req == NULL)
+		return rc;
+	req->ring = ring_id;
+	req->bigendian = false;
+	req->bucketsize = bucket_sz;
+	req->chunksize = chunk_sz;
+	req->clocksource = clk_src;
+	req->enableperiodic = ena_periodic;
+	req->enabledontfreebuffer = ena_dfb;
+	req->interval = interval;
+	req->gpioedge = TIM_GPIO_LTOH_TRANS;
+
+	rc = mbox_process(dev->mbox);
+	if (rc < 0) {
+		tim_err_desc(rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int
+roc_tim_lf_alloc(struct roc_tim *roc_tim, uint8_t ring_id, uint64_t *clk)
+{
+	struct sso *sso = roc_sso_to_sso_priv(roc_tim->roc_sso);
+	struct tim_lf_alloc_req *req;
+	struct tim_lf_alloc_rsp *rsp;
+	struct dev *dev = &sso->dev;
+	int rc = -ENOSPC;
+
+	req = mbox_alloc_msg_tim_lf_alloc(dev->mbox);
+	if (req == NULL)
+		return rc;
+	req->npa_pf_func = idev_npa_pffunc_get();
+	req->sso_pf_func = idev_sso_pffunc_get();
+	req->ring = ring_id;
+
+	rc = mbox_process_msg(dev->mbox, (void **)&rsp);
+	if (rc < 0) {
+		tim_err_desc(rc);
+		return rc;
+	}
+
+	if (clk)
+		*clk = rsp->tenns_clk;
+
+	return rc;
+}
+
+int
+roc_tim_lf_free(struct roc_tim *roc_tim, uint8_t ring_id)
+{
+	struct sso *sso = roc_sso_to_sso_priv(roc_tim->roc_sso);
+	struct dev *dev = &sso->dev;
+	struct tim_ring_req *req;
+	int rc = -ENOSPC;
+
+	req = mbox_alloc_msg_tim_lf_free(dev->mbox);
+	if (req == NULL)
+		return rc;
+	req->ring = ring_id;
+
+	rc = mbox_process(dev->mbox);
+	if (rc < 0) {
+		tim_err_desc(rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int
+roc_tim_init(struct roc_tim *roc_tim)
+{
+	struct rsrc_attach_req *attach_req;
+	struct free_rsrcs_rsp *free_rsrc;
+	struct dev *dev;
+	uint16_t nb_lfs;
+	int rc;
+
+	if (roc_tim == NULL || roc_tim->roc_sso == NULL)
+		return TIM_ERR_PARAM;
+
+	PLT_STATIC_ASSERT(sizeof(struct tim) <= TIM_MEM_SZ);
+	dev = &roc_sso_to_sso_priv(roc_tim->roc_sso)->dev;
+	nb_lfs = roc_tim->nb_lfs;
+	mbox_alloc_msg_free_rsrc_cnt(dev->mbox);
+	rc = mbox_process_msg(dev->mbox, (void *)&free_rsrc);
+	if (rc < 0) {
+		plt_err("Unable to get free rsrc count.");
+		return 0;
+	}
+
+	if (nb_lfs && (free_rsrc->tim < nb_lfs)) {
+		plt_tim_dbg("Requested LFs : %d Available LFs : %d", nb_lfs,
+			    free_rsrc->tim);
+		return 0;
+	}
+
+	attach_req = mbox_alloc_msg_attach_resources(dev->mbox);
+	if (attach_req == NULL)
+		return -ENOSPC;
+	attach_req->modify = true;
+	attach_req->timlfs = nb_lfs ? nb_lfs : free_rsrc->tim;
+	nb_lfs = attach_req->timlfs;
+
+	rc = mbox_process(dev->mbox);
+	if (rc < 0) {
+		plt_err("Unable to attach TIM LFs.");
+		return 0;
+	}
+
+	return nb_lfs;
+}
+
+void
+roc_tim_fini(struct roc_tim *roc_tim)
+{
+	struct dev *dev = &roc_sso_to_sso_priv(roc_tim->roc_sso)->dev;
+	struct rsrc_detach_req *detach_req;
+
+	detach_req = mbox_alloc_msg_detach_resources(dev->mbox);
+	PLT_ASSERT(detach_req);
+	detach_req->partial = true;
+	detach_req->timlfs = true;
+
+	mbox_process(dev->mbox);
+}
diff --git a/drivers/common/cnxk/roc_tim.h b/drivers/common/cnxk/roc_tim.h
new file mode 100644
index 0000000..159b021
--- /dev/null
+++ b/drivers/common/cnxk/roc_tim.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#ifndef _ROC_TIM_H_
+#define _ROC_TIM_H_
+
+enum roc_tim_clk_src {
+	ROC_TIM_CLK_SRC_10NS = 0,
+	ROC_TIM_CLK_SRC_GPIO,
+	ROC_TIM_CLK_SRC_GTI,
+	ROC_TIM_CLK_SRC_PTP,
+	ROC_TIM_CLK_SRC_INVALID,
+};
+
+struct roc_tim {
+	struct roc_sso *roc_sso;
+	/* Public data. */
+	uint16_t nb_lfs;
+	/* Private data. */
+#define TIM_MEM_SZ (1 * 1024)
+	uint8_t reserved[TIM_MEM_SZ] __plt_cache_aligned;
+} __plt_cache_aligned;
+
+int __roc_api roc_tim_init(struct roc_tim *roc_tim);
+void __roc_api roc_tim_fini(struct roc_tim *roc_tim);
+
+/* TIM config */
+int __roc_api roc_tim_lf_enable(struct roc_tim *roc_tim, uint8_t ring_id,
+				uint64_t *start_tsc, uint32_t *cur_bkt);
+int __roc_api roc_tim_lf_disable(struct roc_tim *roc_tim, uint8_t ring_id);
+int __roc_api roc_tim_lf_config(struct roc_tim *roc_tim, uint8_t ring_id,
+				enum roc_tim_clk_src clk_src,
+				uint8_t ena_periodic, uint8_t ena_dfb,
+				uint32_t bucket_sz, uint32_t chunk_sz,
+				uint32_t interval);
+int __roc_api roc_tim_lf_alloc(struct roc_tim *roc_tim, uint8_t ring_id,
+			       uint64_t *clk);
+int __roc_api roc_tim_lf_free(struct roc_tim *roc_tim, uint8_t ring_id);
+uintptr_t __roc_api roc_tim_lf_base_get(struct roc_tim *roc_tim,
+					uint8_t ring_id);
+
+#endif
diff --git a/drivers/common/cnxk/roc_tim_priv.h b/drivers/common/cnxk/roc_tim_priv.h
new file mode 100644
index 0000000..08697f6
--- /dev/null
+++ b/drivers/common/cnxk/roc_tim_priv.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#ifndef _ROC_TIM_PRIV_H_
+#define _ROC_TIM_PRIV_H_
+
+struct tim {
+};
+
+enum tim_err_status {
+	TIM_ERR_PARAM = -5120,
+};
+
+static inline struct tim *
+roc_tim_to_tim_priv(struct roc_tim *roc_tim)
+{
+	return (struct tim *)&roc_tim->reserved[0];
+}
+
+#endif /* _ROC_TIM_PRIV_H_ */
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 1e5e8ab..5f2264f 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -7,6 +7,7 @@ INTERNAL {
 	cnxk_logtype_npa;
 	cnxk_logtype_npc;
 	cnxk_logtype_sso;
+	cnxk_logtype_tim;
 	cnxk_logtype_tm;
 	roc_clk_freq_get;
 	roc_error_msg_get;
@@ -188,6 +189,14 @@ INTERNAL {
 	roc_sso_ns_to_gw;
 	roc_sso_rsrc_fini;
 	roc_sso_rsrc_init;
+	roc_tim_fini;
+	roc_tim_init;
+	roc_tim_lf_alloc;
+	roc_tim_lf_base_get;
+	roc_tim_lf_config;
+	roc_tim_lf_disable;
+	roc_tim_lf_enable;
+	roc_tim_lf_free;
 
 	local: *;
 };
