Tool/software:
Hi, ti expert,
we use SK-AM62A-LP platform, and sdk 09.02.
we use GPMC interface connect to a oled (i-80 mode) module. and use DMA to copy data from frambuffer to oled's gram.
the DMA can work, and oled can display photo but photo color is reversed, red change to blue. The reason is : the oled' gram is Big-endian, and dma wokes at little-endian, dma's address increase from low address to high address. So how can i fix the issue?
I refered to the patch file 3386.udma-dev-to-mem-1019.diff, and patch the drivers\dma\ti\k3-udma.c
the dts and code like this:
&gpmc0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&gpmc0_pins_default>;
assigned-clock-parents = <&k3_clks 80 2>; /*1mclk=10ns*/
assigned-clock-rates = <33333333>; /*33333333 ,30 ns*/
ranges = <1 0 0x00 0x50000000 0x01000000>; /* CS1 space. size = 128MiB*/
oled@1,0 {
compatible = "atmel,unication-oled-module";
reg = <1 0 0x00000004>;
reg-names = "data";
oled_rs = <22>; /* pin index for LCD_RS */
madctl = <0x00>; //bit3:0-rgb, 1-bgr. bit6:1-mirror-x
oled_type = <0x00>;//1: rm96092, 0: FT2308
rotate_degree = <270>; //clockwide, vaild for 0,90,180,270
atmel,oled-has-dma;
atmel,oled-bank-width = <8>; /* 8bit */
dmas = <&main_bcdma 1 0 0>;
dma-names = "tx";
oled_reset-gpios = <&main_gpio0 38 GPIO_ACTIVE_HIGH>;
oled_panel_pw_ctl-gpios = <&main_gpio0 14 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&main_gpio0>;
interrupts = <36 IRQ_TYPE_EDGE_FALLING>; //Tearing Effect(TE) singal
//assigned-clock-parents = <&k3_clks 80 2>; /*1mclk=10ns*/
//assigned-clock-rates = <33333333>; /*33333333 ,30 ns*/
// can read 3208 ID ,can display R G B
// mclk=30 ns
/* CONFIG1*/
bank-width = <1>;
/*gpmc,sync-read;*/
/*gpmc,sync-write;*/
/*gpmc,clk-activation-ns = <0>;*/
gpmc,mux-add-data = <0>;
/* CONFIG2*/
/*gpmc,sync-clk-ps = <0>;*/
gpmc,cs-on-ns = <30>;
gpmc,cs-rd-off-ns = <900>;
gpmc,cs-wr-off-ns = <228>;
/* CONFIG3*/
/*gpmc,adv-on-ns = <35>;*/
/*gpmc,adv-rd-off-ns = <9>;*/
/*gpmc,adv-wr-off-ns = <9>;*/
/* CONFIG4*/
gpmc,we-on-ns = <53>;
gpmc,we-off-ns = <129>;
gpmc,oe-on-ns = <53>;
gpmc,oe-off-ns = <454>;
/* CONFIG5*/
gpmc,access-ns = <454>;
gpmc,rd-cycle-ns = <930>;
gpmc,wr-cycle-ns = <227>;
gpmc,wr-access-ns = <129>;
};
};
static inline int set_dma_config(struct oledfb_dev *oled_dev)
{
int ret;
struct dma_slave_config slave_config;
oled_dev->dma_chan = dma_request_slave_channel(oled_dev->dev, "tx");
if(!oled_dev->dma_chan) {
dev_err(oled_dev->dev, "%s Failed to request DMA channel\n", __FUNCTION__);
return -EINVAL;
}
dev_info(oled_dev->dev, "oled using %s for DMA transfer\n", dma_chan_name(oled_dev->dma_chan));
memset(&slave_config, 0, sizeof(slave_config));
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr_width = 1;
slave_config.dst_maxburst = 1;
slave_config.dst_addr = (dma_addr_t)oled_dev->oled_data_phy_addr;
ret = dmaengine_slave_config(oled_dev->dma_chan, &slave_config);
if(ret) {
dev_err(oled_dev->dev, "error in dma configuration\n");
goto err;
}
return 0;
err:
dma_release_channel(oled_dev->dma_chan);
oled_dev->dma_chan = NULL;
return ret;
}
static inline int prepare_dma_transfer(struct oledfb_dev *oled_dev)
{
struct scatterlist *sgl = &oled_dev->sgl[0];
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = oled_dev->dma_chan;
dma_addr_t p;
if (!oled_dev->dma_chan) {
if (set_dma_config(oled_dev) < 0) {
dev_err(oled_dev->dev, "%s: set_dma_config fail\n", __FUNCTION__);
return -1;
}
}
/*
The maximun transaction units is 0xFFFF length.
We have logo data 448*368*2= 329728bytes to be send, need at least 6 scatters
transactions. 0xFFFF(65535)*4 + 33794*2 =329728bytes.
*/
/* Since ARM's memory is little-endian, while the driver IC needs to be feed
* in big-endian, hence the walk around is setup DMA transfering
* from buffer memory's tail to head, with address decreasing */
sg_init_table(sgl, 6);
p = oled_dev->rotated_framebuf_phy_start;
sg_dma_address(&sgl[0]) = p;
sg_dma_len(&sgl[0]) = 0xFFFF;
p = p + 0xFFFF;
sg_dma_address(&sgl[1]) = p;
sg_dma_len(&sgl[1]) = 0xFFFF;
p = p + 0xFFFF;
sg_dma_address(&sgl[2]) = p;
sg_dma_len(&sgl[2]) = 0xFFFF;
p = p + 0xFFFF;
sg_dma_address(&sgl[3]) = p;
sg_dma_len(&sgl[3]) = 0xFFFF;
p = p + 0xFFFF;
sg_dma_address(&sgl[4]) = p;
sg_dma_len(&sgl[4]) = 33794;
p = p + 33794;
sg_dma_address(&sgl[5]) = p;
sg_dma_len(&sgl[5]) = 33794;
desc = dmaengine_prep_slave_sg(chan, sgl, 6,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT|DMA_CTRL_ACK);
if(desc == NULL) {
dev_err(oled_dev->dev, "get dma desc fail.\n");
return -1;
}
oled_dev->desc_tx = desc;
desc->callback = dma_complete_callback_function;
desc->callback_param = oled_dev;
dma_cookie_t cookie_tx;
/* Start DMA transmition, send RGB data */
cookie_tx = dmaengine_submit(oled_dev->desc_tx);
txchan->device->device_issue_pending(txchan);
return 0;
}
static int update_oled_contents_by_dma(struct oledfb_dev *oled_dev)
{
int ret;
dev_info(oled_dev->dev, "update_oled_contents_by_dma ENTER.\n");
if(oled_dev->desc_tx) {
dev_info(oled_dev->dev, "The old screen update request has not been executed yet!\n");
return 0;
}
ret = prepare_dma_transfer(oled_dev);
if (ret < 0) {
dev_err(oled_dev->dev, "%s: prepare_dma_transfer fail: %d\n", __FUNCTION__, ret);
return ret;
}
if(oled_dev->oled_id == OLED_ID_FT2308)
{
/* Tearing Effect Line OFF */
oled_ft2308_cmd(oled_dev, 0x34);
/* Memory Write */
oled_ft2308_cmd(oled_dev, 0x2C);
}
else
{
/* Tearing Effect Line OFF */
oled_rm69092_cmd(oled_dev, 0x3400);
/* Memory Write */
oled_rm69092_cmd(oled_dev, 0x2C00);
}
struct dma_chan *txchan = oled_dev->dma_chan;
dma_cookie_t cookie_tx;
/* Start DMA transmition, send RGB data */
cookie_tx = dmaengine_submit(oled_dev->desc_tx);
txchan->device->device_issue_pending(txchan);
dev_info(oled_dev->dev, "update_oled_contents_by_dma END. cookie_tx=%d\n", cookie_tx);
return 0;
}
/* Issue pending requests and wait for callback notification */
static void dma_complete_callback_function(void *dma_async_param)
{
struct oledfb_dev *oled_dev = (struct oledfb_dev *)dma_async_param;
struct dma_chan *txchan = oled_dev->dma_chan;
async_tx_ack(oled_dev->desc_tx);
oled_dev->desc_tx = NULL;
oled_dev->refresh_complete = 1;
}











