diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 65040d7..3d021e6 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -52,18 +52,26 @@ enum crb_cancel {
 	CRB_CANCEL_INVOKE	= BIT(0),
 };
 
-struct crb_control_area {
-	u32 req;
-	u32 sts;
-	u32 cancel;
-	u32 start;
-	u32 int_enable;
-	u32 int_sts;
-	u32 cmd_size;
-	u32 cmd_pa_low;
-	u32 cmd_pa_high;
-	u32 rsp_size;
-	u64 rsp_pa;
+struct crb_regs {
+	u32 loc_state;
+	u32 reserved1;
+	u32 loc_ctrl;
+	u32 loc_sts;
+	u8 reserved2[32];
+	u64 intf_id;
+	u64 ctrl_ext;
+	/* the control area */
+	u32 ctrl_req;
+	u32 ctrl_sts;
+	u32 ctrl_cancel;
+	u32 ctrl_start;
+	u32 ctrl_int_enable;
+	u32 ctrl_int_sts;
+	u32 ctrl_cmd_size;
+	u32 ctrl_cmd_pa_low;
+	u32 ctrl_cmd_pa_high;
+	u32 ctrl_rsp_size;
+	u64 ctrl_rsp_pa;
 } __packed;
 
 enum crb_status {
@@ -78,7 +86,7 @@ enum crb_flags {
 struct crb_priv {
 	unsigned int flags;
 	void __iomem *iobase;
-	struct crb_control_area __iomem *cca;
+	struct crb_regs __iomem *regs;
 	u8 __iomem *cmd;
 	u8 __iomem *rsp;
 	u32 cmd_size;
@@ -104,7 +112,7 @@ static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv)
 	if (priv->flags & CRB_FL_ACPI_START)
 		return 0;
 
-	iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req);
+	iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs->ctrl_req);
 	/* we don't really care when this settles */
 
 	return 0;
@@ -128,16 +136,18 @@ static int __maybe_unused crb_cmd_ready(struct device *dev,
 					struct crb_priv *priv)
 {
 	ktime_t stop, start;
+	u32 req;
 
 	if (priv->flags & CRB_FL_ACPI_START)
 		return 0;
 
-	iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req);
+	iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->regs->ctrl_req);
 
 	start = ktime_get();
 	stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C));
 	do {
-		if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) {
+		req = ioread32(&priv->regs->ctrl_req);
+		if (!(req & CRB_CTRL_REQ_CMD_READY)) {
 			dev_dbg(dev, "cmdReady in %lld usecs\n",
 				ktime_to_us(ktime_sub(ktime_get(), start)));
 			return 0;
@@ -145,7 +155,7 @@ static int __maybe_unused crb_cmd_ready(struct device *dev,
 		usleep_range(50, 100);
 	} while (ktime_before(ktime_get(), stop));
 
-	if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) {
+	if (ioread32(&priv->regs->ctrl_req) & CRB_CTRL_REQ_CMD_READY) {
 		dev_warn(dev, "cmdReady timed out\n");
 		return -ETIME;
 	}
@@ -158,7 +168,7 @@ static u8 crb_status(struct tpm_chip *chip)
 	struct crb_priv *priv = dev_get_drvdata(&chip->dev);
 	u8 sts = 0;
 
-	if ((ioread32(&priv->cca->start) & CRB_START_INVOKE) !=
+	if ((ioread32(&priv->regs->ctrl_start) & CRB_START_INVOKE) !=
 	    CRB_START_INVOKE)
 		sts |= CRB_DRV_STS_COMPLETE;
 
@@ -174,7 +184,7 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	if (count < 6)
 		return -EIO;
 
-	if (ioread32(&priv->cca->sts) & CRB_CTRL_STS_ERROR)
+	if (ioread32(&priv->regs->ctrl_sts) & CRB_CTRL_STS_ERROR)
 		return -EIO;
 
 	memcpy_fromio(buf, priv->rsp, 6);
@@ -213,7 +223,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
 	/* Zero the cancel register so that the next command will not get
 	 * canceled.
 	 */
-	iowrite32(0, &priv->cca->cancel);
+	iowrite32(0, &priv->regs->ctrl_cancel);
 
 	if (len > priv->cmd_size) {
 		dev_err(&chip->dev, "invalid command count value %zd %d\n",
@@ -227,7 +237,7 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
 	wmb();
 
 	if (priv->flags & CRB_FL_CRB_START)
-		iowrite32(CRB_START_INVOKE, &priv->cca->start);
+		iowrite32(CRB_START_INVOKE, &priv->regs->ctrl_start);
 
 	if (priv->flags & CRB_FL_ACPI_START)
 		rc = crb_do_acpi_start(chip);
@@ -239,7 +249,7 @@ static void crb_cancel(struct tpm_chip *chip)
 {
 	struct crb_priv *priv = dev_get_drvdata(&chip->dev);
 
-	iowrite32(CRB_CANCEL_INVOKE, &priv->cca->cancel);
+	iowrite32(CRB_CANCEL_INVOKE, &priv->regs->ctrl_cancel);
 
 	if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
 		dev_err(&chip->dev, "ACPI Start failed\n");
@@ -248,7 +258,7 @@ static void crb_cancel(struct tpm_chip *chip)
 static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
 {
 	struct crb_priv *priv = dev_get_drvdata(&chip->dev);
-	u32 cancel = ioread32(&priv->cca->cancel);
+	u32 cancel = ioread32(&priv->regs->ctrl_cancel);
 
 	return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
 }
@@ -302,6 +312,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
 	struct list_head resources;
 	struct resource io_res;
 	struct device *dev = &device->dev;
+	void *ctrl;
 	u32 pa_high, pa_low;
 	u64 cmd_pa;
 	u32 cmd_size;
@@ -325,10 +336,17 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
 	if (IS_ERR(priv->iobase))
 		return PTR_ERR(priv->iobase);
 
-	priv->cca = crb_map_res(dev, priv, &io_res, buf->control_address,
-				sizeof(struct crb_control_area));
-	if (IS_ERR(priv->cca))
-		return PTR_ERR(priv->cca);
+	ctrl = crb_map_res(dev, priv, &io_res, buf->control_address,
+			   sizeof(struct crb_regs) -
+			   offsetof(struct crb_regs, ctrl_req));
+	if (IS_ERR(ctrl))
+		return PTR_ERR(ctrl);
+
+	/* The control area always overrlaps IO memory mapped from the ACPI
+	 * object with CRB start only devices. Thus, this is perfectly safe.
+	 */
+	priv->regs = (void *)((unsigned long)ctrl -
+		offsetof(struct crb_regs, ctrl_req));
 
 	/*
 	 * PTT HW bug w/a: wake up the device to access
@@ -338,10 +356,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
 	if (ret)
 		return ret;
 
-	pa_high = ioread32(&priv->cca->cmd_pa_high);
-	pa_low  = ioread32(&priv->cca->cmd_pa_low);
+	pa_high = ioread32(&priv->regs->ctrl_cmd_pa_high);
+	pa_low  = ioread32(&priv->regs->ctrl_cmd_pa_low);
 	cmd_pa = ((u64)pa_high << 32) | pa_low;
-	cmd_size = ioread32(&priv->cca->cmd_size);
+	cmd_size = ioread32(&priv->regs->ctrl_cmd_size);
 
 	dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n",
 		pa_high, pa_low, cmd_size);
@@ -352,9 +370,9 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
 		goto out;
 	}
 
-	memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8);
+	memcpy_fromio(&rsp_pa, &priv->regs->ctrl_rsp_pa, 8);
 	rsp_pa = le64_to_cpu(rsp_pa);
-	rsp_size = ioread32(&priv->cca->rsp_size);
+	rsp_size = ioread32(&priv->regs->ctrl_rsp_size);
 
 	if (cmd_pa != rsp_pa) {
 		priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size);
