How to enable UART DMA mode on Hikey960?

Hi.
I found that bluetooth service crash always occurs with Sony Headsets supporting LDAC when a2dp streaming.
The root cause is that UART H/W error events are raised from Bluetooth HCI layer. Hikey960 has the TI BT&WI combo chip, and uses UART2 port and 3M baudrate to communicate with it. I guess that this issue is related to no DMA support for UART2 on Hikey960. As far as I know, if we use 3M baudrate for UART transfer, need to support DMA due to performace issues like this issue. I think that Bluetooth PAN, OPP services would have same issue caused by UART performace. Because these services need high UART transfer performace.

Could you let me know how to enable UART DMA mode on Hikey960? Currently, I’m using AOSP build and 4.9 kernel.

Thanks,

1 Like

I’ve probably seen this same problem. My needs involve PAN, and I’ve had bluetooth die out on me shortly after start of modest data transfers. I’ve had to fall back to wifi for data, which makes no sense if there is already a bluetooth connection.

I filed a bug report way back in april, but no action on it: https://bugs.96boards.org/show_bug.cgi?id=730

Maybe @Loic can help, since he’s managed other life saving wireless fixes (:wink: :wink:): Wifi does not connect to the router/phone hotspot with AOSP prebuilt image - #10 by Loic

Hi @danny81,

According to the DTS [1], BT chip is connected to UART4. Anyway, for enabling UART DMA, you can use following properties in corresponding UART nodes in DT.

serial0: uart@fdf02000 {
...
			dmas =  <&dma0 0	&dma0 1>;
			dma-names = "rx", "tx";
...
}

serial1: uart@fdf00000  {
...
			dmas =  <&dma0 2	&dma0 3>;
			dma-names = "rx", "tx";
...
}

serial2: uart@fdf03000 {
...
			dmas =  <&dma0 4	&dma0 5>;
			dma-names = "rx", "tx";
...
}

serial4: uart@fdf01000 {
...
			dmas =  <&dma0 6	&dma0 7>;
			dma-names = "rx", "tx";
...
}

serial5: uart@fdf05000 {
...
			dmas =  <&dma0 8	&dma0 9>;
			dma-names = "rx", "tx";
...
}

For BT UART DMA, I think you can use the DMA properties in serial4.

Thanks,
Mani

[1] https://github.com/96boards-hikey/linux/blob/hikey960-upstream-rebase/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts#L238

Hi Mani,

Thanks a lot for your response. You’re right. BT Chip is connected to UART4. Unfortunately, I’ve already tried to add the dma properties for UART4 in dts file but if we enable DMA as you suggesed, UART doesn’t work. Currenlty, Hikey960 uses DMA0 and channel 0~3 are assigned for SPI. So, I used DMA0 4 and 5 for UART4 but it doesn’t work. In this case, I confirmed “uart-pl011 fdf01000.serial: no DMA platform data” message is not displayed anymore in kernel log.

Thanks,
Danny

@danny81, Where did you get the SPI DMA info.? Because, AFAIK SPI DMA channels starts from 10. I have referred the publicly available Huawei Hi3660 SoC source [1]. I think you should be able to use channels 6 & 7 for BT (UART4).

[1] https://github.com/Ante0/MHA-NG_EMUI5.0_opensource/blob/master/kernel/arch/arm64/boot/dts/auto-generate/hisi_3660_spi.dtsi

Currently, below messages are printed in kernel log. So, I though SPI uses DMA0 from channel 0 to 3 on Hikey960 based on kernel 4.9 version.

[ 6.835017] ssp-pl022 ffd68000.spi: ARM PL022 driver, device ID: 0x00041022
[ 6.842088] ssp-pl022 ffd68000.spi: mapped registers from 0x00000000ffd68000 to ffffff800bb11000
[ 6.851004] ssp-pl022 ffd68000.spi: setup for DMA on RX dma0chan0, TX dma0chan1
[ 6.859002] ssp-pl022 ff3b3000.spi: ARM PL022 driver, device ID: 0x00041022
[ 6.866059] ssp-pl022 ff3b3000.spi: mapped registers from 0x00000000ff3b3000 to ffffff800bb13000
[ 6.874971] ssp-pl022 ff3b3000.spi: setup for DMA on RX dma0chan2, TX dma0chan3

For your information, I’m using android-hikey-linaro-4.9 kernel branch for Hikey960 AOSP build.

Thanks,

Currently, below messages are printed in kernel log. So, I though SPI uses DMA0 from channel 0 to 3 on Hikey960 based on kernel 4.9 version.

Hmm. But I can’t find the relevant DMA properties in DTS [1]. Did you customise it?

Thanks,
Mani

[1] arch/arm64/boot/dts/hisilicon/hi3660.dtsi - kernel/hikey-linaro - Git at Google

No, I didn’t. I found another person updated same log messages.

Thanks,

I’m sorry for confusing you. Please refer to below.

Thanks,
Danny

Hi Mani,

I found that there is no DMA0 properity in hi3660.dtsi in android-hikey-linaro-4.9.

https://android.googlesource.com/kernel/hikey-linaro/+/android-hikey-linaro-4.9/arch/arm64/boot/dts/hisilicon/hi3660.dtsi

But I found android-hikey-linaro-4.14 has the DMA0 properity using K3 DMA like below.

https://android.googlesource.com/kernel/hikey-linaro/+/android-hikey-linaro-4.14/arch/arm64/boot/dts/hisilicon/hi3660.dtsi

	dma0: dma@fdf30000 {
		compatible = "hisilicon,k3-dma-1.0";
		reg = <0x0 0xfdf30000 0x0 0x1000>;
		#dma-cells = <1>;
		dma-channels = <16>;
		dma-requests = <32>;
		dma-min-chan = <1>;
		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&crg_ctrl HI3660_CLK_GATE_DMAC>;
		dma-no-cci;
		dma-type = "hi3660_dma";
	};

Also, this need to add CONFIG_K3_DMA=y in hikey960_defconfig.

I just tried this changes with your solution but UART4 didn’t work.

Thanks,

Hi @danny81,

I found that there is no DMA0 properity in hi3660.dtsi in android-hikey-linaro-4.9.

Yes. This means that no slave device is currently using DMA.

But I found android-hikey-linaro-4.14 has the DMA0 properity using K3 DMA like below.

K3 DMA is the DMA driver for controlling the DMA engine in HiKey960. It is not a property. Property is what used by DMA slave devices like UART in this case for using the DMA engine to copy data.

Also, this need to add CONFIG_K3_DMA=y in hikey960_defconfig.

Isn’t it enabled by default?

I just tried this changes with your solution but UART4 didn’t work.

Can you please clarify what didn’t work? Is the UART driver not able to use DMA or UART driver is using DMA but still the BT issue persists?

It would be great if you can share your hi3660.dtsi file after modification.

Thanks,
Mani

Hi Mani,

[Danny]Yes, need CONFIG_K3_DMA=y to include K3 DMA in build time. please refer to blow Makefile.

obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
obj-$(CONFIG_K3_DMA) += k3dma.o
obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o

[Mani]Can you please clarify what didn’t work? Is the UART driver not able to use DMA or UART driver is using DMA but still the BT issue persists?

[Danny] If I enable DMA for UART4, below messages are printed in kernel log.
But BT host stack can’t communicate with BT controller via UART4. According to adb log, BT host stack try to send HCI command via UART4 but doesn’t receive any reponse from BT controller.

[ 6.795185] ffd74000.serial: ttyAMA3 at MMIO 0xffd74000 (irq = 21, base_baud = 0) is a PL011 rev2
[ 6.804559] fdf01000.serial: ttyAMA4 at MMIO 0xfdf01000 (irq = 22, base_baud = 0) is a PL011 rev2
[ 6.813651] serial serial0: tty port ttyAMA4 registered
[ 6.818988] uart-pl011 fdf01000.serial: DMA channel TX dma0chan7
[ 18.138142] uart-pl011 fdf01000.serial: DMA channel RX dma0chan6

[Mani]It would be great if you can share your hi3660.dtsi file after modification.

[Danny]Here are my changes in hi3660.dtsi file.

		uart4: serial@fdf01000 {
		compatible = "arm,pl011", "arm,primecell";
		reg = <0x0 0xfdf01000 0x0 0x1000>;
		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
		dmas = <&dma0 6 &dma0 7>;
		dma-names = "rx", "tx";
		clocks = <&crg_ctrl HI3660_CLK_GATE_UART4>,
			 <&crg_ctrl HI3660_CLK_GATE_UART4>;
		clock-names = "uartclk", "apb_pclk";
		pinctrl-names = "default";
		pinctrl-0 = <&uart4_pmx_func &uart4_cfg_func>;
		status = "disabled";
	};

	dma0: dma@fdf30000 {
		compatible = "hisilicon,k3-dma-1.0";
		reg = <0x0 0xfdf30000 0x0 0x1000>;
		#dma-cells = <1>;
		dma-channels = <16>;
		dma-requests = <32>;
		dma-min-chan = <1>;
		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
		clocks = <&crg_ctrl HI3660_CLK_GATE_DMAC>;
		dma-no-cci;
		dma-type = "hi3660_dma";
	};

Thanks,

Question:

Is it actually setting the baud rate to 3M? Or is it just attempting to?
It seems to be set to 921600 here; https://android.googlesource.com/kernel/hikey-linaro/+/android-hikey-linaro-4.9/arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts#376

Now 921600 may still be higher than the interface reliably supports. There are some interesting notes above and below that line, /* baud_rate = <230400>; ok */ and /* baud_rate = <1500000>; nok */

I’m sorry for missing one thing that I modified. Acutally, I found this problem when using 921600 baudrate. So, I tried to apply latest kernel changes for TI BT controller. For your information, Hikey960 kernel 4.14 version uses 3M baud like below.

hi3660-hikey960.dts

&uart4 {
status = “okay”;

bluetooth {
	compatible = "ti,wl1837-st";
	enable-gpios = <&gpio15 6 GPIO_ACTIVE_HIGH>;
	max-speed = <3000000>;
};

};

Anyway, I think that need to use DMA for high spped UART transfer.

Thanks,

Ok, that makes more sense.
However the interesting thing is that both 4.4 and 4.14 kernels have it set to 3M, but neither have DMA enabled for it. Does it actually work with 3M on those kernels? Or is it exhibiting the same problem?

Can you provide a clip of your logs showing the error? Does it look similar to the error in this log? https://bugs.96boards.org/attachment.cgi?id=256 (look around line 325).

Note that that log is using PAN at 921600.

EDIT: Have you tested at other speeds to see if there is some cutoff where it works well at lower speeds? 3M is a lot higher than you should need for any kind of audio transfer.

Hi Mani,

I tried to enable UART DMA with the K3 DMA engine based on android-hikey-linaro-4.9 kernel branch. But I got failed to enable UART DMA on Hikey960.
After enable DMA for UART4, “Bluetooth: Unknown HCI packet type 00” error messages are printed consistently. This means that PL011 AMBA and K3 DMA drivers fill the TTY UART buffer with only NULL data.

[ 2.888406] k3-dma fdf30000.dma: initialized
[ 2.890120] hisi-asp-dma e804b000.asp_dmac: initialized
[ 2.891844] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled


[ 6.786317] ffd74000.serial: ttyAMA3 at MMIO 0xffd74000 (irq = 21, base_baud = 0) is a PL011 rev2
[ 6.795696] fdf01000.serial: ttyAMA4 at MMIO 0xfdf01000 (irq = 22, base_baud = 0) is a PL011 rev2
[ 6.804838] serial serial0: tty port ttyAMA4 registered
[ 6.810335] uart-pl011 fdf01000.serial: DMA channel TX dma0chan7
[ 6.810389] ssp-pl022 ffd68000.spi: ARM PL022 driver, device ID: 0x00041022
[ 6.810420] ssp-pl022 ffd68000.spi: mapped registers from 0x00000000ffd68000 to ffffff800bb11000
[ 6.810460] ssp-pl022 ffd68000.spi: setup for DMA on RX dma0chan0, TX dma0chan1
[ 6.810898] ssp-pl022 ff3b3000.spi: ARM PL022 driver, device ID: 0x00041022
[ 6.810922] ssp-pl022 ff3b3000.spi: mapped registers from 0x00000000ff3b3000 to ffffff800bb13000
[ 6.810952] ssp-pl022 ff3b3000.spi: setup for DMA on RX dma0chan2, TX dma0chan3


[ 7.319823] [E/hisi_pd] pd_dpm_handle_pe_event:!!!,event=5,+++
[ 7.319833] Pending event is same → ignore this event 2
[ 7.319977] [E/hisi_pd] pd_dpm_handle_pe_event:!!!,event=3,+++
[ 7.763067] uart-pl011 fdf01000.serial: DMA channel RX dma0chan6
[ 7.796377] [drm] Initialized kirin 1.0.0 20170309 on minor 0
[ 7.802512] dwmmc_k3 ff3ff000.dwmmc2: fifo-depth property not found, using value of FIFOTH register as default
[ 7.814758] dwmmc_k3 ff3ff000.dwmmc2: IDMAC supports 64-bit address mode.
[ 7.821666] dwmmc_k3 ff3ff000.dwmmc2: Using internal DMA controller.
[ 7.828096] dwmmc_k3 ff3ff000.dwmmc2: Version ID is 270a
[ 7.833525] dwmmc_k3 ff3ff000.dwmmc2: DW MMC controller at irq 64,32 bit host data width,128 deep fifo
[ 7.892010] Bluetooth: Unknown HCI packet type 00
[ 7.897037] Bluetooth: Unknown HCI packet type 00
[ 7.901857] Bluetooth: Unknown HCI packet type 00
[ 7.906662] Bluetooth: Unknown HCI packet type 00
[ 7.911530] Bluetooth: Unknown HCI packet type 00
[ 7.916586] Bluetooth: Unknown HCI packet type 00
[ 7.921371] Bluetooth: Unknown HCI packet type 00
[ 7.926148] Bluetooth: Unknown HCI packet type 00
[ 7.930921] Bluetooth: Unknown HCI packet type 00
[ 7.935750] Bluetooth: Unknown HCI packet type 00
[ 7.940519] Bluetooth: Unknown HCI packet type 00
[ 7.942371] mmc_host mmc1: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
[ 7.954650] Bluetooth: Unknown HCI packet type 00
[ 7.959413] Bluetooth: Unknown HCI packet type 00
[ 7.960394] dwmmc_k3 ff3ff000.dwmmc2: 1 slots initialized
[ 7.961133] hisi_i2s e804f000.hisi_i2s: Failed to get DMA channel capabilities, falling back to period counting: -6
[ 7.961139] asoc-simple-card soc:sound: hdmi-hifi.0 <-> hisi_i2s2 mapping ok
[ 7.961373] hisi_i2s_plat soc:hisi_i2s_plat: Failed to get DMA channel capabilities, falling back to period counting: -6
[ 7.961475] hisi_i2s_plat soc:hisi_i2s_plat: Failed to get DMA channel capabilities, falling back to period counting: -6
[ 7.961480] asoc-simple-card soc:sound: virtual-dai <-> hisi_i2s0 mapping ok
[ 7.963354] otg_wakelock_init: No USB transceiver found
[ 7.963973] input: keys as /devices/platform/keys/input/input0
[ 7.964452] rtc-pl031 fff04000.rtc: setting system clock to 1970-01-01 00:18:58 UTC (1138)
[ 7.964950] ALSA device list:
[ 7.964953] #0: hikey-sndcard
[ 7.984711] dwmmc_k3 ff3ff000.dwmmc2: card claims to support voltages below defined range
[ 8.001328] mmc_host mmc1: Bus speed (slot 0) = 25000000Hz (slot req 25000000Hz, actual 25000000HZ div = 0)
[ 8.004736] mmc1: new SDIO card at address 0001
[ 8.005800] wl18xx_driver wl18xx.0.auto: Direct firmware load for ti-connectivity/wl18xx-conf.bin failed with error -2
[ 8.005803] wl18xx_driver wl18xx.0.auto: Falling back to user helper
[ 8.082378] Bluetooth: Unknown HCI packet type 00
[ 8.082379] Bluetooth: Unknown HCI packet type 00
[ 8.082381] Bluetooth: Unknown HCI packet type 00
[ 8.082382] Bluetooth: Unknown HCI packet type 00
[ 8.082383] Bluetooth: Unknown HCI packet type 00
[ 8.082384] Bluetooth: Unknown HCI packet type 00
[ 8.082384] Bluetooth: Unknown HCI packet type 00
[ 8.082385] Bluetooth: Unknown HCI packet type 00
[ 8.082386] Bluetooth: Unknown HCI packet type 00
[ 8.082388] Bluetooth: Unknown HCI packet type 00
[ 8.082389] Bluetooth: Unknown HCI packet type 00
[ 8.082389] Bluetooth: Unknown HCI packet type 00

It seems that the K3 DMA driver doesn’t support UART DMA properly. According to the k3_dma_config function in the k3dma.c file, it set CX_CONFIG to CX_CFG_MEM2PER only regardless of DMA direction. We need both DMA_DEV_TO_MEM and DMA_MEM_TO_DEV directions for UART DMA support, and it seems that need to set CX_CONFIG to CX_CFG_PER2MEM for DMA_DEV_TO_MEM direction.

I need your help to enable UART DMA for high speed UART support. Also, I made a bug report. https://bugs.96boards.org/show_bug.cgi?id=766

static int k3_dma_config(struct dma_chan *chan,
struct dma_slave_config *cfg)
{
struct k3_dma_chan *c = to_k3_chan(chan);
u32 maxburst = 0, val = 0;
enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;

if (cfg == NULL)
	return -EINVAL;
c->dir = cfg->direction;
if (c->dir == DMA_DEV_TO_MEM) {
	c->ccfg = CX_CFG_DSTINCR;
	c->dev_addr = cfg->src_addr;
	maxburst = cfg->src_maxburst;
	width = cfg->src_addr_width;
} else if (c->dir == DMA_MEM_TO_DEV) {
	c->ccfg = CX_CFG_SRCINCR;
	c->dev_addr = cfg->dst_addr;
	maxburst = cfg->dst_maxburst;
	width = cfg->dst_addr_width;
}
switch (width) {
case DMA_SLAVE_BUSWIDTH_1_BYTE:
case DMA_SLAVE_BUSWIDTH_2_BYTES:
case DMA_SLAVE_BUSWIDTH_4_BYTES:
case DMA_SLAVE_BUSWIDTH_8_BYTES:
	val =  __ffs(width);
	break;
default:
	val = 3;
	break;
}
c->ccfg |= (val << 12) | (val << 16);

if ((maxburst == 0) || (maxburst > 16))
	val = 15;
else
	val = maxburst - 1;
c->ccfg |= (val << 20) | (val << 24);
c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;

/* specific request line */
c->ccfg |= c->vc.chan.chan_id << 4;

return 0;

}

Thanks,
Danny

Hi @danny81,

Agree! The flow control mode for DMA transfer should be changed according to the transfer direction. Will look into this issue and get back to you shortly.

Thanks for reporting!

Regards,
Mani

Hi @danny81,

Can you please apply the below diff and test it again?

diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 01d2a75..b7d97c2 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -58,6 +58,7 @@
 #define CX_LLI_CHAIN_EN                0x2
 #define CX_CFG_EN              0x1
 #define CX_CFG_NODEIRQ         BIT(1)
+#define CX_CFG_FLOWMASK                GENMASK(3,2)
 #define CX_CFG_MEM2PER         (0x1 << 2)
 #define CX_CFG_PER2MEM         (0x2 << 2)
 #define CX_CFG_SRCINCR         (0x1 << 31)
@@ -648,13 +649,14 @@ static int k3_dma_config(struct dma_chan *chan,
        if (cfg == NULL)
                return -EINVAL;
        c->dir = cfg->direction;
+       c->ccfg &= ~CX_CFG_FLOWMASK;
        if (c->dir == DMA_DEV_TO_MEM) {
-               c->ccfg = CX_CFG_DSTINCR;
+               c->ccfg = CX_CFG_DSTINCR | CX_CFG_PER2MEM;
                c->dev_addr = cfg->src_addr;
                maxburst = cfg->src_maxburst;
                width = cfg->src_addr_width;
        } else if (c->dir == DMA_MEM_TO_DEV) {
-               c->ccfg = CX_CFG_SRCINCR;
+               c->ccfg = CX_CFG_SRCINCR | CX_CFG_MEM2PER;
                c->dev_addr = cfg->dst_addr;
                maxburst = cfg->dst_maxburst;
                width = cfg->dst_addr_width;
@@ -677,7 +679,7 @@ static int k3_dma_config(struct dma_chan *chan,
        else
                val = maxburst - 1;
        c->ccfg |= (val << 20) | (val << 24);
-       c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;
+       c->ccfg |= CX_CFG_EN;
 
        /* specific request line */
        c->ccfg |= c->vc.chan.chan_id << 4;

PS: I haven’t tested this change.

I saw one more issue where MEMCPY is not working properly but it should not affect your case.

Thanks,
Mani

Hi Mani,

I got same result. Even if apply your solution, “Bluetooth: Unknown HCI packet type 00” error messages are printed consistently. Does it need to set AXI_CFG for DMA_DEV_TO_MEM directon?

Thanks,
Danny

Hi @danny81,

Apart from the public datasheet available, I don’t have access to any DMA documentation. Will see if I can escalate it to HiSilicon.

Thanks,
Mani