diff options
author | Thang Q. Nguyen <tqnguyen@apm.com> | 2012-05-10 00:17:10 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2012-07-25 15:54:21 -0400 |
commit | dc7f71f486f4f5fa96f6dcf86833da020cde8a11 (patch) | |
tree | 0f8b83ed3584b270b24dd61f1f9b5b543536f24e | |
parent | facb8fa6c784893ad1da9f0fd160e3b3c5fad2c4 (diff) |
sata_dwc_460ex: device tree may specify dma_channel
Only channel 0 is currently support and the driver code is fixed on
channel 0. This patch lets device node specifying dma-channel in case
it is not 0. If no dma-channel property is specified, channel 0 is
used as default.
Signed-off-by: Thang Q. Nguyen <tqnguyen@apm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rwxr-xr-x[-rw-r--r--] | drivers/ata/sata_dwc_460ex.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index ae13ef1945ba..937aeb34b310 100644..100755 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c | |||
@@ -158,6 +158,7 @@ enum { | |||
158 | /* Assign HW handshaking interface (x) to destination / source peripheral */ | 158 | /* Assign HW handshaking interface (x) to destination / source peripheral */ |
159 | #define DMA_CFG_HW_HS_DEST(int_num) (((int_num) & 0xF) << 11) | 159 | #define DMA_CFG_HW_HS_DEST(int_num) (((int_num) & 0xF) << 11) |
160 | #define DMA_CFG_HW_HS_SRC(int_num) (((int_num) & 0xF) << 7) | 160 | #define DMA_CFG_HW_HS_SRC(int_num) (((int_num) & 0xF) << 7) |
161 | #define DMA_CFG_HW_CH_PRIOR(int_num) (((int_num) & 0xF) << 5) | ||
161 | #define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master)) | 162 | #define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master)) |
162 | 163 | ||
163 | /* | 164 | /* |
@@ -318,6 +319,7 @@ struct sata_dwc_host_priv { | |||
318 | u32 dma_interrupt_count; | 319 | u32 dma_interrupt_count; |
319 | struct ahb_dma_regs *sata_dma_regs; | 320 | struct ahb_dma_regs *sata_dma_regs; |
320 | struct device *dwc_dev; | 321 | struct device *dwc_dev; |
322 | int dma_channel; | ||
321 | }; | 323 | }; |
322 | struct sata_dwc_host_priv host_pvt; | 324 | struct sata_dwc_host_priv host_pvt; |
323 | /* | 325 | /* |
@@ -437,15 +439,12 @@ static void clear_chan_interrupts(int c) | |||
437 | */ | 439 | */ |
438 | static int dma_request_channel(void) | 440 | static int dma_request_channel(void) |
439 | { | 441 | { |
440 | int i; | 442 | /* Check if the channel is not currently in use */ |
441 | 443 | if (!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) & | |
442 | for (i = 0; i < DMA_NUM_CHANS; i++) { | 444 | DMA_CHANNEL(host_pvt.dma_channel))) |
443 | if (!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) &\ | 445 | return host_pvt.dma_channel; |
444 | DMA_CHANNEL(i))) | 446 | dev_err(host_pvt.dwc_dev, "%s Channel %d is currently in use\n", |
445 | return i; | 447 | __func__, host_pvt.dma_channel); |
446 | } | ||
447 | dev_err(host_pvt.dwc_dev, "%s NO channel chan_en: 0x%08x\n", __func__, | ||
448 | in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low))); | ||
449 | return -1; | 448 | return -1; |
450 | } | 449 | } |
451 | 450 | ||
@@ -481,7 +480,8 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance) | |||
481 | dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n", | 480 | dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n", |
482 | tfr_reg, err_reg, hsdevp->dma_pending[tag], port); | 481 | tfr_reg, err_reg, hsdevp->dma_pending[tag], port); |
483 | 482 | ||
484 | for (chan = 0; chan < DMA_NUM_CHANS; chan++) { | 483 | chan = host_pvt.dma_channel; |
484 | if (chan >= 0) { | ||
485 | /* Check for end-of-transfer interrupt. */ | 485 | /* Check for end-of-transfer interrupt. */ |
486 | if (tfr_reg & DMA_CHANNEL(chan)) { | 486 | if (tfr_reg & DMA_CHANNEL(chan)) { |
487 | /* | 487 | /* |
@@ -534,9 +534,9 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance) | |||
534 | static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq) | 534 | static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq) |
535 | { | 535 | { |
536 | int retval = 0; | 536 | int retval = 0; |
537 | int chan; | 537 | int chan = host_pvt.dma_channel; |
538 | 538 | ||
539 | for (chan = 0; chan < DMA_NUM_CHANS; chan++) { | 539 | if (chan >= 0) { |
540 | /* Unmask error interrupt */ | 540 | /* Unmask error interrupt */ |
541 | out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.error.low, | 541 | out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.error.low, |
542 | DMA_ENABLE_CHAN(chan)); | 542 | DMA_ENABLE_CHAN(chan)); |
@@ -575,7 +575,10 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems, | |||
575 | int fis_len = 0; | 575 | int fis_len = 0; |
576 | dma_addr_t next_llp; | 576 | dma_addr_t next_llp; |
577 | int bl; | 577 | int bl; |
578 | int sms_val, dms_val; | ||
578 | 579 | ||
580 | sms_val = 0; | ||
581 | dms_val = 1 + host_pvt.dma_channel; | ||
579 | dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x" | 582 | dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x" |
580 | " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli, | 583 | " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli, |
581 | (u32)dmadr_addr); | 584 | (u32)dmadr_addr); |
@@ -635,8 +638,8 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems, | |||
635 | 638 | ||
636 | lli[idx].ctl.low = cpu_to_le32( | 639 | lli[idx].ctl.low = cpu_to_le32( |
637 | DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) | | 640 | DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) | |
638 | DMA_CTL_SMS(0) | | 641 | DMA_CTL_SMS(sms_val) | |
639 | DMA_CTL_DMS(1) | | 642 | DMA_CTL_DMS(dms_val) | |
640 | DMA_CTL_SRC_MSIZE(bl) | | 643 | DMA_CTL_SRC_MSIZE(bl) | |
641 | DMA_CTL_DST_MSIZE(bl) | | 644 | DMA_CTL_DST_MSIZE(bl) | |
642 | DMA_CTL_SINC_NOCHANGE | | 645 | DMA_CTL_SINC_NOCHANGE | |
@@ -651,8 +654,8 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems, | |||
651 | 654 | ||
652 | lli[idx].ctl.low = cpu_to_le32( | 655 | lli[idx].ctl.low = cpu_to_le32( |
653 | DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) | | 656 | DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) | |
654 | DMA_CTL_SMS(1) | | 657 | DMA_CTL_SMS(dms_val) | |
655 | DMA_CTL_DMS(0) | | 658 | DMA_CTL_DMS(sms_val) | |
656 | DMA_CTL_SRC_MSIZE(bl) | | 659 | DMA_CTL_SRC_MSIZE(bl) | |
657 | DMA_CTL_DST_MSIZE(bl) | | 660 | DMA_CTL_DST_MSIZE(bl) | |
658 | DMA_CTL_DINC_NOCHANGE | | 661 | DMA_CTL_DINC_NOCHANGE | |
@@ -744,8 +747,10 @@ static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems, | |||
744 | 747 | ||
745 | /* Program the CFG register. */ | 748 | /* Program the CFG register. */ |
746 | out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high), | 749 | out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high), |
750 | DMA_CFG_HW_HS_SRC(dma_ch) | DMA_CFG_HW_HS_DEST(dma_ch) | | ||
747 | DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ); | 751 | DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ); |
748 | out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low), 0); | 752 | out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low), |
753 | DMA_CFG_HW_CH_PRIOR(dma_ch)); | ||
749 | 754 | ||
750 | /* Program the address of the linked list */ | 755 | /* Program the address of the linked list */ |
751 | out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low), | 756 | out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low), |
@@ -1660,6 +1665,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) | |||
1660 | struct ata_host *host; | 1665 | struct ata_host *host; |
1661 | struct ata_port_info pi = sata_dwc_port_info[0]; | 1666 | struct ata_port_info pi = sata_dwc_port_info[0]; |
1662 | const struct ata_port_info *ppi[] = { &pi, NULL }; | 1667 | const struct ata_port_info *ppi[] = { &pi, NULL }; |
1668 | struct device_node *np = ofdev->dev.of_node; | ||
1669 | u32 dma_chan; | ||
1663 | 1670 | ||
1664 | /* Allocate DWC SATA device */ | 1671 | /* Allocate DWC SATA device */ |
1665 | hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); | 1672 | hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); |
@@ -1669,6 +1676,13 @@ static int sata_dwc_probe(struct platform_device *ofdev) | |||
1669 | goto error; | 1676 | goto error; |
1670 | } | 1677 | } |
1671 | 1678 | ||
1679 | if (of_property_read_u32(np, "dma-channel", &dma_chan)) { | ||
1680 | dev_warn(&ofdev->dev, "no dma-channel property set." | ||
1681 | " Use channel 0\n"); | ||
1682 | dma_chan = 0; | ||
1683 | } | ||
1684 | host_pvt.dma_channel = dma_chan; | ||
1685 | |||
1672 | /* Ioremap SATA registers */ | 1686 | /* Ioremap SATA registers */ |
1673 | base = of_iomap(ofdev->dev.of_node, 0); | 1687 | base = of_iomap(ofdev->dev.of_node, 0); |
1674 | if (!base) { | 1688 | if (!base) { |