forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
coresight: tmc: splitting driver in ETB/ETF and ETR components
The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed via two interfaces (sysFS and Perf). That makes 6 mode to cover, which is way too much coupling for a single file. This patch splits the original TMC driver in 2 halves, one for ETB/ETF and another one for ETR mode. A common core is kept for functionality common to all 3 modes. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- Loading branch information
1 parent
a8ab426
commit 6c6ed1e
Showing
5 changed files
with
357 additions
and
261 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
/* | ||
* Copyright(C) 2016 Linaro Limited. All rights reserved. | ||
* Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 as published by | ||
* the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
* more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along with | ||
* this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <linux/coresight.h> | ||
#include "coresight-priv.h" | ||
#include "coresight-tmc.h" | ||
|
||
void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
/* Zero out the memory to help with debug */ | ||
memset(drvdata->buf, 0, drvdata->size); | ||
|
||
CS_UNLOCK(drvdata->base); | ||
|
||
/* Wait for TMCSReady bit to be set */ | ||
tmc_wait_for_tmcready(drvdata); | ||
|
||
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); | ||
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | | ||
TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | | ||
TMC_FFCR_TRIGON_TRIGIN, | ||
drvdata->base + TMC_FFCR); | ||
|
||
writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); | ||
tmc_enable_hw(drvdata); | ||
|
||
CS_LOCK(drvdata->base); | ||
} | ||
|
||
static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
enum tmc_mem_intf_width memwidth; | ||
u8 memwords; | ||
char *bufp; | ||
u32 read_data; | ||
int i; | ||
|
||
memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10); | ||
if (memwidth == TMC_MEM_INTF_WIDTH_32BITS) | ||
memwords = 1; | ||
else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS) | ||
memwords = 2; | ||
else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS) | ||
memwords = 4; | ||
else | ||
memwords = 8; | ||
|
||
bufp = drvdata->buf; | ||
while (1) { | ||
for (i = 0; i < memwords; i++) { | ||
read_data = readl_relaxed(drvdata->base + TMC_RRD); | ||
if (read_data == 0xFFFFFFFF) | ||
return; | ||
memcpy(bufp, &read_data, 4); | ||
bufp += 4; | ||
} | ||
} | ||
} | ||
|
||
void tmc_etb_disable_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
CS_UNLOCK(drvdata->base); | ||
|
||
tmc_flush_and_stop(drvdata); | ||
tmc_etb_dump_hw(drvdata); | ||
tmc_disable_hw(drvdata); | ||
|
||
CS_LOCK(drvdata->base); | ||
} | ||
|
||
static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
CS_UNLOCK(drvdata->base); | ||
|
||
/* Wait for TMCSReady bit to be set */ | ||
tmc_wait_for_tmcready(drvdata); | ||
|
||
writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE); | ||
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI, | ||
drvdata->base + TMC_FFCR); | ||
writel_relaxed(0x0, drvdata->base + TMC_BUFWM); | ||
tmc_enable_hw(drvdata); | ||
|
||
CS_LOCK(drvdata->base); | ||
} | ||
|
||
static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
CS_UNLOCK(drvdata->base); | ||
|
||
tmc_flush_and_stop(drvdata); | ||
tmc_disable_hw(drvdata); | ||
|
||
CS_LOCK(drvdata->base); | ||
} | ||
|
||
static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode) | ||
{ | ||
unsigned long flags; | ||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
|
||
spin_lock_irqsave(&drvdata->spinlock, flags); | ||
if (drvdata->reading) { | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
return -EBUSY; | ||
} | ||
|
||
tmc_etb_enable_hw(drvdata); | ||
drvdata->enable = true; | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
|
||
dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n"); | ||
return 0; | ||
} | ||
|
||
static void tmc_disable_etf_sink(struct coresight_device *csdev) | ||
{ | ||
unsigned long flags; | ||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
|
||
spin_lock_irqsave(&drvdata->spinlock, flags); | ||
if (drvdata->reading) { | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
return; | ||
} | ||
|
||
tmc_etb_disable_hw(drvdata); | ||
drvdata->enable = false; | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
|
||
dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n"); | ||
} | ||
|
||
static int tmc_enable_etf_link(struct coresight_device *csdev, | ||
int inport, int outport) | ||
{ | ||
unsigned long flags; | ||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
|
||
spin_lock_irqsave(&drvdata->spinlock, flags); | ||
if (drvdata->reading) { | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
return -EBUSY; | ||
} | ||
|
||
tmc_etf_enable_hw(drvdata); | ||
drvdata->enable = true; | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
|
||
dev_info(drvdata->dev, "TMC-ETF enabled\n"); | ||
return 0; | ||
} | ||
|
||
static void tmc_disable_etf_link(struct coresight_device *csdev, | ||
int inport, int outport) | ||
{ | ||
unsigned long flags; | ||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
|
||
spin_lock_irqsave(&drvdata->spinlock, flags); | ||
if (drvdata->reading) { | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
return; | ||
} | ||
|
||
tmc_etf_disable_hw(drvdata); | ||
drvdata->enable = false; | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
|
||
dev_info(drvdata->dev, "TMC disabled\n"); | ||
} | ||
|
||
static const struct coresight_ops_sink tmc_etf_sink_ops = { | ||
.enable = tmc_enable_etf_sink, | ||
.disable = tmc_disable_etf_sink, | ||
}; | ||
|
||
static const struct coresight_ops_link tmc_etf_link_ops = { | ||
.enable = tmc_enable_etf_link, | ||
.disable = tmc_disable_etf_link, | ||
}; | ||
|
||
const struct coresight_ops tmc_etb_cs_ops = { | ||
.sink_ops = &tmc_etf_sink_ops, | ||
}; | ||
|
||
const struct coresight_ops tmc_etf_cs_ops = { | ||
.sink_ops = &tmc_etf_sink_ops, | ||
.link_ops = &tmc_etf_link_ops, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Copyright(C) 2016 Linaro Limited. All rights reserved. | ||
* Author: Mathieu Poirier <mathieu.poirier@linaro.org> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 as published by | ||
* the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
* more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along with | ||
* this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <linux/coresight.h> | ||
#include "coresight-priv.h" | ||
#include "coresight-tmc.h" | ||
|
||
void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
u32 axictl; | ||
|
||
/* Zero out the memory to help with debug */ | ||
memset(drvdata->vaddr, 0, drvdata->size); | ||
|
||
CS_UNLOCK(drvdata->base); | ||
|
||
/* Wait for TMCSReady bit to be set */ | ||
tmc_wait_for_tmcready(drvdata); | ||
|
||
writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ); | ||
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); | ||
|
||
axictl = readl_relaxed(drvdata->base + TMC_AXICTL); | ||
axictl |= TMC_AXICTL_WR_BURST_16; | ||
writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | ||
axictl &= ~TMC_AXICTL_SCT_GAT_MODE; | ||
writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | ||
axictl = (axictl & | ||
~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) | | ||
TMC_AXICTL_PROT_CTL_B1; | ||
writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | ||
|
||
writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO); | ||
writel_relaxed(0x0, drvdata->base + TMC_DBAHI); | ||
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | | ||
TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | | ||
TMC_FFCR_TRIGON_TRIGIN, | ||
drvdata->base + TMC_FFCR); | ||
writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); | ||
tmc_enable_hw(drvdata); | ||
|
||
CS_LOCK(drvdata->base); | ||
} | ||
|
||
static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
u32 rwp, val; | ||
|
||
rwp = readl_relaxed(drvdata->base + TMC_RWP); | ||
val = readl_relaxed(drvdata->base + TMC_STS); | ||
|
||
/* How much memory do we still have */ | ||
if (val & BIT(0)) | ||
drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; | ||
else | ||
drvdata->buf = drvdata->vaddr; | ||
} | ||
|
||
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) | ||
{ | ||
CS_UNLOCK(drvdata->base); | ||
|
||
tmc_flush_and_stop(drvdata); | ||
tmc_etr_dump_hw(drvdata); | ||
tmc_disable_hw(drvdata); | ||
|
||
CS_LOCK(drvdata->base); | ||
} | ||
|
||
static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode) | ||
{ | ||
unsigned long flags; | ||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
|
||
spin_lock_irqsave(&drvdata->spinlock, flags); | ||
if (drvdata->reading) { | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
return -EBUSY; | ||
} | ||
|
||
tmc_etr_enable_hw(drvdata); | ||
drvdata->enable = true; | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
|
||
dev_info(drvdata->dev, "TMC-ETR enabled\n"); | ||
return 0; | ||
} | ||
|
||
static void tmc_disable_etr_sink(struct coresight_device *csdev) | ||
{ | ||
unsigned long flags; | ||
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||
|
||
spin_lock_irqsave(&drvdata->spinlock, flags); | ||
if (drvdata->reading) { | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
return; | ||
} | ||
|
||
tmc_etr_disable_hw(drvdata); | ||
drvdata->enable = false; | ||
spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||
|
||
dev_info(drvdata->dev, "TMC-ETR disabled\n"); | ||
} | ||
|
||
static const struct coresight_ops_sink tmc_etr_sink_ops = { | ||
.enable = tmc_enable_etr_sink, | ||
.disable = tmc_disable_etr_sink, | ||
}; | ||
|
||
const struct coresight_ops tmc_etr_cs_ops = { | ||
.sink_ops = &tmc_etr_sink_ops, | ||
}; |
Oops, something went wrong.