diff options
Diffstat (limited to 'arch')
18 files changed, 575 insertions, 293 deletions
diff --git a/arch/arm/configs/tegra_harmony_android_defconfig b/arch/arm/configs/tegra_harmony_android_defconfig index 489e7e6253a9..c24816c5b36b 100644 --- a/arch/arm/configs/tegra_harmony_android_defconfig +++ b/arch/arm/configs/tegra_harmony_android_defconfig @@ -1484,6 +1484,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_MMC_SDHCI=y # CONFIG_MMC_SDHCI_PCI is not set CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK=y # CONFIG_MMC_TIFM_SD is not set # CONFIG_MMC_SPI is not set # CONFIG_MEMSTICK is not set diff --git a/arch/arm/configs/tegra_whistler_android_defconfig b/arch/arm/configs/tegra_whistler_android_defconfig index fe2839172cd2..6e341676dba1 100644 --- a/arch/arm/configs/tegra_whistler_android_defconfig +++ b/arch/arm/configs/tegra_whistler_android_defconfig @@ -1199,6 +1199,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_MMC_SDHCI_DYNAMIC_SDMEM_CLOCK=y # CONFIG_MMC_SPI is not set # CONFIG_MEMSTICK is not set # CONFIG_ACCESSIBILITY is not set diff --git a/arch/arm/mach-tegra/board_nvodm.c b/arch/arm/mach-tegra/board_nvodm.c index 237844085c84..b1404b6ff00f 100644 --- a/arch/arm/mach-tegra/board_nvodm.c +++ b/arch/arm/mach-tegra/board_nvodm.c @@ -26,6 +26,7 @@ #include <linux/platform_device.h> #include <linux/synaptics_i2c_rmi.h> #include <linux/i2c.h> +#include <linux/pm.h> #include <linux/spi/spi.h> #include <asm/mach-types.h> @@ -56,7 +57,6 @@ #include "mach/nvrm_linux.h" #include "nvassert.h" #include "nvodm_query_discovery.h" -#include "mach/pci.h" #include <../../../drivers/staging/android/timed_output.h> @@ -277,13 +277,13 @@ static void __init NvConfigDebugConsole( return; } -void __init pci_tegra_power(int on) +void tegra_set_voltage(NvU64 guid, int on) { u32 settling_time; const NvOdmPeripheralConnectivity *con = NULL; int i; - con = NvOdmPeripheralGetGuid(NV_VDD_PEX_CLK_ODM_ID); + con = NvOdmPeripheralGetGuid(guid); if (con == NULL) return; @@ -311,6 +311,12 @@ extern void __init tegra_clk_init(void); extern void __init tegra_init_snor_controller(void); #endif + +static void tegra_system_power_off(void) +{ + tegra_set_voltage(NV_VDD_SoC_ODM_ID, 0); +} + #if !(defined(CONFIG_ENC28J60) && defined(CONFIG_SPI_TEGRA)) #define register_enc28j60() do {} while (0) #else @@ -476,11 +482,12 @@ static void __init tegra_machine_init(void) #endif #ifdef CONFIG_TEGRA_PCI - pci_tegra_power(1); + tegra_set_voltage( NV_VDD_PEX_CLK_ODM_ID, 1); #else - pci_tegra_power(0); + tegra_set_voltage( NV_VDD_PEX_CLK_ODM_ID, 0); #endif + pm_power_off = tegra_system_power_off; } MACHINE_START(TEGRA_GENERIC, "Tegra generic") diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index fa4186513ce5..bbd3691240ea 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -78,8 +78,6 @@ struct tegra_dma_channel { unsigned long phys_addr; int mode; - int odd_interrupt; - /* Register shadow */ unsigned long csr; unsigned long ahb_seq; @@ -102,7 +100,6 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch); void tegra_dma_flush(int channel) { - } EXPORT_SYMBOL(tegra_dma_flush); @@ -142,6 +139,8 @@ int tegra_dma_dequeue_req(int channel, struct tegra_dma_req *_req) struct tegra_dma_req *req = NULL; int found = 0; unsigned long irq_flags; + int to_transfer; + int req_transfer_count; spin_lock_irqsave(&ch->lock, irq_flags); list_for_each_entry (req, &ch->list, list) { @@ -151,80 +150,102 @@ int tegra_dma_dequeue_req(int channel, struct tegra_dma_req *_req) break; } } - BUG_ON(found==0); - - if (found) { - int to_transfer; - int req_transfer_count; - - /* STOP the DMA and get the transfer count. - * Getting the transfer count is tricky. - * - Change the source selector to invalid to stop the DMA from - * FIFO to memory. - * - Read the status register to knoe the number of pending - * bytes to be transfered. - * - Finally stop or program the DMA to the next buffer in the - * list. - */ - csr = ch->csr; - csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR, - REQ_SEL, NA31, csr); - /* Set the enable as that is not shadowed */ - csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR, - ENB, ENABLE, csr); - writel(csr, ch->addr + APBDMACHAN_CHANNEL_0_CSR_0); - - /* Get the transfer count */ - status = readl(ch->addr + APBDMACHAN_CHANNEL_0_STA_0); - to_transfer = NV_DRF_VAL(APBDMACHAN_CHANNEL_0, STA, - COUNT, status); - req_transfer_count = NV_DRF_VAL(APBDMACHAN_CHANNEL_0, - CSR, WCOUNT, ch->csr); - - req->bytes_transferred = req_transfer_count - to_transfer; - req->bytes_transferred *= 4; - - tegra_dma_stop(ch); - if (!list_empty(&ch->list)) { - /* if the list is not empty, queue the next request */ - struct tegra_dma_req *next_req; - next_req = list_entry(ch->list.next, - typeof(*next_req), list); - tegra_dma_update_hw(ch, next_req); - } - req->status = -TEGRA_DMA_REQ_ERROR_ABOTRED; - + if (found==0) { spin_unlock_irqrestore(&ch->lock, irq_flags); - req->complete(req, req->status); - spin_lock_irqsave(&ch->lock, irq_flags); + return 0; + } + + /* STOP the DMA and get the transfer count. + * Getting the transfer count is tricky. + * - Change the source selector to invalid to stop the DMA from + * FIFO to memory. + * - Read the status register to know the number of pending + * bytes to be transfered. + * - Finally stop or program the DMA to the next buffer in the + * list. + */ + csr = ch->csr; + csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR, + REQ_SEL, NA31, csr); + /* Set the enable as that is not shadowed */ + csr = NV_FLD_SET_DRF_DEF(APBDMACHAN_CHANNEL_0, CSR, + ENB, ENABLE, csr); + writel(csr, ch->addr + APBDMACHAN_CHANNEL_0_CSR_0); + + /* Get the transfer count */ + status = readl(ch->addr + APBDMACHAN_CHANNEL_0_STA_0); + to_transfer = NV_DRF_VAL(APBDMACHAN_CHANNEL_0, STA, + COUNT, status); + req_transfer_count = NV_DRF_VAL(APBDMACHAN_CHANNEL_0, + CSR, WCOUNT, ch->csr); + + req->bytes_transferred = req_transfer_count - to_transfer; + req->bytes_transferred *= 4; + /* In continous transfer mode, DMA only tracks the count of the + * half DMA buffer. So, if the DMA already finished half the DMA + * then add the half buffer to the completed count. + * + * FIXME: There can be a race here. What if the req to + * dequue happens at the same time as the DMA just moved to + * the new buffer and SW didn't yet received the interrupt? + */ + if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) + if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) { + req->bytes_transferred += 4 * req_transfer_count; + } + tegra_dma_stop(ch); + if (!list_empty(&ch->list)) { + /* if the list is not empty, queue the next request */ + struct tegra_dma_req *next_req; + next_req = list_entry(ch->list.next, + typeof(*next_req), list); + tegra_dma_update_hw(ch, next_req); } + req->status = -TEGRA_DMA_REQ_ERROR_ABOTRED; + spin_unlock_irqrestore(&ch->lock, irq_flags); - if (found) - return 0; - else - return -ENOENT; + /* Callback should be called without any lock */ + req->complete(req, req->status); + return 0; } EXPORT_SYMBOL(tegra_dma_dequeue_req); -int tegra_dma_is_empty(int channel) +bool tegra_dma_is_empty(int channel) { unsigned long irq_flags; struct tegra_dma_channel *ch = &dma_channels[channel]; - int is_empty; + bool is_empty; spin_lock_irqsave(&ch->lock, irq_flags); if (list_empty(&ch->list)) - is_empty = 1; + is_empty = true; else - is_empty = 0; + is_empty = false; spin_unlock_irqrestore(&ch->lock, irq_flags); - return is_empty; } EXPORT_SYMBOL(tegra_dma_is_empty); +bool tegra_dma_is_req_inflight(int channel, struct tegra_dma_req *_req) +{ + unsigned long irq_flags; + struct tegra_dma_channel *ch = &dma_channels[channel]; + struct tegra_dma_req *req; + + spin_lock_irqsave(&ch->lock, irq_flags); + list_for_each_entry (req, &ch->list, list) { + if (req == _req) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + return true; + } + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return false; +} +EXPORT_SYMBOL(tegra_dma_is_req_inflight); + int tegra_dma_enqueue_req(int channel, struct tegra_dma_req *req) { unsigned long irq_flags; @@ -241,6 +262,7 @@ int tegra_dma_enqueue_req(int channel, struct tegra_dma_req *req) req->bytes_transferred = 0; req->status = 0; + req->buffer_status = 0; if (list_empty(&ch->list)) start_dma = 1; @@ -466,9 +488,11 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch) { static struct tegra_dma_req *req; - if (list_empty(&ch->list)) - /* Why did we got an interrupt? */ + spin_lock(&ch->lock); + if (list_empty(&ch->list)) { + spin_unlock(&ch->lock); return; + } req = list_entry(ch->list.next, typeof(*req), list); if (req) { @@ -483,33 +507,51 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch) list_del(&req->list); req->bytes_transferred = bytes_transferred; req->status = 0; + + spin_unlock(&ch->lock); + /* Callback should be called without any lock */ req->complete(req, 0); + spin_lock(&ch->lock); } if (!list_empty(&ch->list)) { req = list_entry(ch->list.next, typeof(*req), list); tegra_dma_update_hw(ch, req); } + spin_unlock(&ch->lock); } static void handle_continuous_dma(struct tegra_dma_channel *ch) { static struct tegra_dma_req *req; - if (list_empty(&ch->list)) - /* Why did we got an interrupt? */ + spin_lock(&ch->lock); + if (list_empty(&ch->list)) { + spin_unlock(&ch->lock); return; + } req = list_entry(ch->list.next, typeof(*req), list); if (req) { - ch->odd_interrupt = (~ch->odd_interrupt & 0x1); - if (ch->odd_interrupt) { - struct tegra_dma_req *next_req; - /* Load the next request into the hardware */ - next_req = list_first_entry(ch->list.next, - typeof(*next_req), list); - tegra_dma_update_hw_partial(ch, next_req); - } else { + if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) { + /* Load the next request into the hardware, if available + * */ + if (!list_is_last(&req->list, &ch->list)) { + struct tegra_dma_req *next_req; + + printk("Queue the next request\n"); + next_req = list_entry(req->list.next, + typeof(*next_req), list); + tegra_dma_update_hw_partial(ch, next_req); + } + req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL; + /* DMA lock is NOT held when callbak is called */ + spin_unlock(&ch->lock); + req->threshold(req, 0); + return; + + } else if (req->buffer_status == + TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) { /* Callback when the buffer is completely full (i.e on * the second interrupt */ int bytes_transferred; @@ -519,12 +561,21 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch) bytes_transferred += 1; bytes_transferred <<= 3; + req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL; req->bytes_transferred = bytes_transferred; req->status = 0; list_del(&req->list); + + /* DMA lock is NOT held when callbak is called */ + spin_unlock(&ch->lock); req->complete(req, 0); + return; + + } else { + BUG(); } } + spin_unlock(&ch->lock); } static irqreturn_t dma_isr(int irq, void *id) @@ -546,6 +597,7 @@ static irqreturn_t dma_isr(int irq, void *id) else handle_continuous_dma(ch); + return IRQ_HANDLED; } @@ -608,4 +660,3 @@ fail: /* FIXME cleanup */ return ret; } - diff --git a/arch/arm/mach-tegra/include/mach/board.h b/arch/arm/mach-tegra/include/mach/board.h index 10f0f0232b90..51e85fdb7bb5 100644 --- a/arch/arm/mach-tegra/include/mach/board.h +++ b/arch/arm/mach-tegra/include/mach/board.h @@ -22,5 +22,11 @@ #define __MACH_TEGRA_BOARD_H #include <linux/types.h> +#include "nvodm_pmu.h" +#include "mach/nvrm_linux.h" +#include "nvodm_query_discovery.h" + +/* ON/off power rail given the GUID */ +void tegra_set_voltage(NvU64 guid, int on); #endif diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h index 964af099a392..508e2fcf8409 100644 --- a/arch/arm/mach-tegra/include/mach/dma.h +++ b/arch/arm/mach-tegra/include/mach/dma.h @@ -34,12 +34,46 @@ enum tegra_dma_req_error { TEGRA_DMA_REQ_ERROR_ABOTRED, }; +enum tegra_dma_req_buff_status { + TEGRA_DMA_REQ_BUF_STATUS_EMPTY, + TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL, + TEGRA_DMA_REQ_BUF_STATUS_FULL, +}; + struct tegra_dma_req { struct list_head list; unsigned int modid; int instance; + /* Called when the req is complete and from the DMA ISR context. + * When this is called the req structure is no longer queued by + * the DMA channel. + * + * State of the DMA depends on the number of req it has. If there are + * no DMA requests queued up, then it will STOP the DMA. It there are + * more requests in the DMA, then it will queue the next request. + */ void (*complete)(struct tegra_dma_req *req, int err); + + /* This is a called from the DMA ISR context when the DMA is still in + * progress and is actively filling same buffer. + * + * In case of continous mode receive, this threshold is 1/2 the buffer + * size. In other cases, this will not even be called as there is no + * hardware support for it. + * + * In the case of continous mode receive, if there is next req already + * queued, DMA programs the HW to use that req when this req is + * completed. If there is no "next req" queued, then DMA ISR doesn't do + * anything before calling this callback. + * + * This is mainly used by the cases, where the clients has queued + * only one req and want to get some sort of DMA threshold + * callback to program the next buffer. + * + */ + void (*threshold)(struct tegra_dma_req *req, int err); + /* 1 to copy to memory. * 0 to copy from the memory to device FIFO */ int to_memory; @@ -57,6 +91,9 @@ struct tegra_dma_req { int bytes_transferred; int status; + /* DMA completion tracking information */ + int buffer_status; + /* Client specific data */ void *data; }; @@ -64,12 +101,11 @@ struct tegra_dma_req { int tegra_dma_enqueue_req(int channel, struct tegra_dma_req *req); int tegra_dma_dequeue_req(int channel, struct tegra_dma_req *req); void tegra_dma_dequeue(int channel); - -/* Returns 1 if there are DMA is empty. - */ -int tegra_dma_is_empty(int channel); void tegra_dma_flush(int channel); +bool tegra_dma_is_req_inflight(int channel, struct tegra_dma_req *req); +bool tegra_dma_is_empty(int channel); + int tegra_dma_allocate_channel(int mode); void tegra_dma_free_channel(int channel); diff --git a/arch/arm/mach-tegra/include/mach/pci.h b/arch/arm/mach-tegra/include/mach/pci.h index 81f149717d05..e5eac3ad5640 100644 --- a/arch/arm/mach-tegra/include/mach/pci.h +++ b/arch/arm/mach-tegra/include/mach/pci.h @@ -320,6 +320,4 @@ static inline void __iomem *pci_tegra_config_addr(u8 bus_number, void pci_tegra_enumerate(void); -void __init pci_tegra_power(int on); - #endif diff --git a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c index fe3c3252d39f..435ff7dcc54c 100755..100644 --- a/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c +++ b/arch/arm/mach-tegra/nvddk/nvddk_usbphy.c @@ -47,6 +47,10 @@ #define MAX_USB_INSTANCES 5 +// On platforms that never disable USB controller clock, use 1KHz as an +// indicator that USB controller is idle, and core voltage can be scaled down +#define USBC_IDLE_KHZ (1) + static NvDdkUsbPhy *s_pUsbPhy = NULL; static NvDdkUsbPhyUtmiPadConfig *s_pUtmiPadConfig = NULL; @@ -247,22 +251,54 @@ UsbPhyDfsBusyHint( { NvRmDfsClockId_Emc, 0, 0, NV_TRUE }, { NvRmDfsClockId_Ahb, 0, 0, NV_TRUE } }; + NvError e = NvSuccess; pUsbHintOn[0].BoostDurationMs = BoostDurationMs; pUsbHintOn[1].BoostDurationMs = BoostDurationMs; if (DfsOn) + { + if (hUsbPhy->Caps.PhyRegInController) + { + // Indicate USB controller is active + NvRmFreqKHz PrefFreq = NvRmPowerModuleGetMaxFrequency( + hUsbPhy->hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance)); + + NV_CHECK_ERROR_CLEANUP( + NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), + hUsbPhy->RmPowerClientId, PrefFreq, PrefFreq, &PrefFreq, + 1, NULL, 0)); + } return NvRmPowerBusyHintMulti(hUsbPhy->hRmDevice, hUsbPhy->RmPowerClientId, pUsbHintOn, NV_ARRAY_SIZE(pUsbHintOn), NvRmDfsBusyHintSyncMode_Async); + } else + { + if (hUsbPhy->Caps.PhyRegInController) + { + // Indicate USB controller is idle + NvRmFreqKHz PrefFreq = USBC_IDLE_KHZ; + + NV_CHECK_ERROR_CLEANUP( + NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), + hUsbPhy->RmPowerClientId, PrefFreq, PrefFreq, &PrefFreq, + 1, NULL, 0)); + } return NvRmPowerBusyHintMulti(hUsbPhy->hRmDevice, hUsbPhy->RmPowerClientId, pUsbHintOff, NV_ARRAY_SIZE(pUsbHintOff), NvRmDfsBusyHintSyncMode_Async); + } + +fail: + return e; } @@ -274,7 +310,8 @@ UsbPhyInitialize( NvRmFreqKHz CurrentFreq = 0; NvRmFreqKHz PrefFreqList[3] = {12000, 60000, NvRmFreqUnspecified}; - //NvOsDebugPrintf("UsbPhyInitialize::VOLTAGE ON\n"); + // NvOsDebugPrintf("UsbPhyInitialize::VOLTAGE ON, instance %d\n", + // hUsbPhy->Instance); // request power NV_CHECK_ERROR_CLEANUP( NvRmPowerVoltageControl(hUsbPhy->hRmDevice, @@ -288,23 +325,31 @@ UsbPhyInitialize( NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), hUsbPhy->RmPowerClientId, NV_TRUE)); - if (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy) + if (!hUsbPhy->Caps.PhyRegInController) { - /* Request for 60MHz clk */ - NV_CHECK_ERROR_CLEANUP( - NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice, - NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), - hUsbPhy->RmPowerClientId, PrefFreqList[1], - PrefFreqList[1], &PrefFreqList[1], 1, &CurrentFreq, 0)); + if (hUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy) + { + /* Request for 60MHz clk */ + NV_CHECK_ERROR_CLEANUP( + NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), + hUsbPhy->RmPowerClientId, PrefFreqList[1], + PrefFreqList[1], &PrefFreqList[1], 1, &CurrentFreq, 0)); + } + else + { + /* Request for 12 MHz clk */ + NV_CHECK_ERROR_CLEANUP( + NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), + hUsbPhy->RmPowerClientId, PrefFreqList[0], + PrefFreqList[0], &PrefFreqList[0], 1, &CurrentFreq, 0)); + } } - else + // else { - /* Request for 12 MHz clk */ - NV_CHECK_ERROR_CLEANUP( - NvRmPowerModuleClockConfig(hUsbPhy->hRmDevice, - NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, hUsbPhy->Instance), - hUsbPhy->RmPowerClientId, PrefFreqList[0], - PrefFreqList[0], &PrefFreqList[0], 1, &CurrentFreq, 0)); + /* No need for actual clock configuration - all USB PLL frequencies + are available concurrently in this case. */ } // Reset controller diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c index 198a2b20ce3d..70138eae4d7c 100644 --- a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c +++ b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_clock_config.c @@ -1279,7 +1279,8 @@ NvRmPrivAp15IsModuleClockException( Ap15PllUConfigure(hRmDevice, PrefFreqList[0]); pCstate->SourceClock = 0; pCstate->Divider = 1; - pCstate->actual_freq = PrefFreqList[0]; + pCstate->actual_freq = + NvRmPrivGetClockSourceFreq(pCinfo->Sources[0]); return NV_TRUE; default: diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c b/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c index 87775f87a4db..8ae5c9dfba72 100644 --- a/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c +++ b/arch/arm/mach-tegra/nvrm/core/ap15/nvrm_clocks.c @@ -1471,9 +1471,9 @@ NvRmPowerModuleClockConfig ( // Display configuration always at nominal voltage. UART divider is not // in CAR, and clock state contains source, rather than UART frequency. - // Hence, get ready for fastest clock. For other modules use maximum of - // target and current frequency. Make sure voltage is high enough for - // maximum module source frequency. + // Hence, get ready for fastest clock. Same for USB clock. For other + // modules use maximum of target and current frequency. Make sure that + // voltage is high enough for maximum module source frequency. if ((ModuleName == NvRmModuleID_Display) || (ModuleName == NvRmModuleID_Dsi)) { @@ -1482,7 +1482,8 @@ NvRmPowerModuleClockConfig ( } else { - if (ModuleName == NvRmModuleID_Uart) + if ((ModuleName == NvRmModuleID_Uart) || + (ModuleName == NvRmModuleID_Usb2Otg)) f = NvRmFreqMaximum; else f = NV_MAX(MaxFreq, state->actual_freq); @@ -1664,7 +1665,7 @@ leave: (ModuleName == NvRmModuleID_Dsi) || state->Vscale)) { // Tune voltage level to the actually configured frequency; for Display - // and UART, use maximum requested frequency. Make sure voltage is + // UART, and USB use maximum requested frequency. Make sure voltage is // updated after display configuration, which may change DVFS clocks. SourceClockFreq = s_ClockSourceFreq[(cinfo->Sources[state->SourceClock])]; @@ -1685,7 +1686,8 @@ leave: } else { - if (ModuleName == NvRmModuleID_Uart) + if ((ModuleName == NvRmModuleID_Uart) || + (ModuleName == NvRmModuleID_Usb2Otg)) f = MaxFreq; else f = state->actual_freq; diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c index 6e61ddd95135..0f7a09446876 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c @@ -37,6 +37,9 @@ #define MAX8907B_I2C_SPEED_KHZ 400 #define MAX8907B_I2C_RETRY_CNT 2 +// Maximum i2c transaction count +#define MAX_TRANSACTION_COUNT 5 + NvBool Max8907bI2cWrite8( NvOdmPmuDeviceHandle hDevice, NvU8 Addr, @@ -45,14 +48,14 @@ NvBool Max8907bI2cWrite8( NvU32 i; NvU8 WriteBuffer[2]; NvOdmI2cTransactionInfo TransactionInfo; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { WriteBuffer[0] = Addr & 0xFF; // PMU offset WriteBuffer[1] = Data & 0xFF; // written data - + TransactionInfo.Address = hPmu->DeviceAddr; TransactionInfo.Buf = &WriteBuffer[0]; TransactionInfo.Flags = NVODM_I2C_IS_WRITE; @@ -69,12 +72,12 @@ NvBool Max8907bI2cWrite8( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -86,28 +89,30 @@ NvBool Max8907bI2cRead8( { NvU32 i; NvU8 ReadBuffer = 0; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo[2]; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { + NvU32 TransactionCount = 0; // Write the PMU offset ReadBuffer = Addr & 0xFF; - TransactionInfo[0].Address = hPmu->DeviceAddr; - TransactionInfo[0].Buf = &ReadBuffer; - TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; - TransactionInfo[0].NumBytes = 1; + TransactionInfo[TransactionCount].Address = hPmu->DeviceAddr; + TransactionInfo[TransactionCount].Buf = &ReadBuffer; + TransactionInfo[TransactionCount].Flags = + NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; + TransactionInfo[TransactionCount++].NumBytes = 1; - TransactionInfo[1].Address = (hPmu->DeviceAddr | 0x1); - TransactionInfo[1].Buf = &ReadBuffer; - TransactionInfo[1].Flags = 0; - TransactionInfo[1].NumBytes = 1; + TransactionInfo[TransactionCount].Address = (hPmu->DeviceAddr | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; // Read data from PMU at the specified offset - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 2, - MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], + TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) { @@ -120,12 +125,12 @@ NvBool Max8907bI2cRead8( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -137,13 +142,13 @@ NvBool Max8907bI2cWrite32( { NvU32 i; NvU8 WriteBuffer[5]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { - WriteBuffer[0] = (NvU8)(Addr & 0xFF); + WriteBuffer[0] = (NvU8)(Addr & 0xFF); WriteBuffer[1] = (NvU8)((Data >> 24) & 0xFF); WriteBuffer[2] = (NvU8)((Data >> 16) & 0xFF); WriteBuffer[3] = (NvU8)((Data >> 8) & 0xFF); @@ -154,7 +159,7 @@ NvBool Max8907bI2cWrite32( TransactionInfo.Flags = NVODM_I2C_IS_WRITE; TransactionInfo.NumBytes = 5; - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) @@ -165,12 +170,12 @@ NvBool Max8907bI2cWrite32( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -182,30 +187,32 @@ NvBool Max8907bI2cRead32( { NvU32 i; NvU8 ReadBuffer[5]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo[2]; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { + NvU32 TransactionCount = 0; ReadBuffer[0] = Addr & 0xFF; - TransactionInfo[0].Address = hPmu->DeviceAddr; - TransactionInfo[0].Buf = &ReadBuffer[0]; - TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; - TransactionInfo[0].NumBytes = 1; + TransactionInfo[TransactionCount].Address = hPmu->DeviceAddr; + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = + NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; + TransactionInfo[TransactionCount++].NumBytes = 1; - TransactionInfo[1].Address = (hPmu->DeviceAddr | 0x1); - TransactionInfo[1].Buf = &ReadBuffer[0]; - TransactionInfo[1].Flags = 0; - TransactionInfo[1].NumBytes = 4; + TransactionInfo[TransactionCount].Address = (hPmu->DeviceAddr | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 4; - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 2, - MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], + TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) { - *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | + *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | (ReadBuffer[2] << 8) | ReadBuffer[3]; return NV_TRUE; @@ -216,12 +223,12 @@ NvBool Max8907bI2cRead32( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -233,13 +240,14 @@ NvBool Max8907bRtcI2cWriteTime( { NvU32 i; NvU8 WriteBuffer[5]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo; + NVODMPMU_PRINTF(("\n RTC I2C write: Addr=0x%x, Data=0x%x ", Addr, Data)); for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { - WriteBuffer[0] = (NvU8)(Addr & 0xFF); + WriteBuffer[0] = (NvU8)(Addr & 0xFF); WriteBuffer[1] = (NvU8)((Data >> 24) & 0xFF); WriteBuffer[2] = (NvU8)((Data >> 16) & 0xFF); WriteBuffer[3] = (NvU8)((Data >> 8) & 0xFF); @@ -250,7 +258,7 @@ NvBool Max8907bRtcI2cWriteTime( TransactionInfo.Flags = NVODM_I2C_IS_WRITE; TransactionInfo.NumBytes = 5; - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) @@ -261,12 +269,12 @@ NvBool Max8907bRtcI2cWriteTime( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -278,46 +286,63 @@ NvBool Max8907bRtcI2cReadTime( { NvU32 i; NvU8 ReadBuffer[4]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; - NvOdmI2cTransactionInfo TransactionInfo[4]; + NvOdmI2cTransactionInfo TransactionInfo[MAX_TRANSACTION_COUNT]; + NVODMPMU_PRINTF(("\n RTC I2C read: Addr=0x%x ", Addr)); for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { - ReadBuffer[0] = Addr++ & 0xFF; - ReadBuffer[1] = Addr++ & 0xFF; - ReadBuffer[2] = Addr++ & 0xFF; - ReadBuffer[3] = 0; - - TransactionInfo[0].Address = MAX8907B_RTC_SLAVE_ADDR; - TransactionInfo[0].Buf = &ReadBuffer[0]; - TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; - TransactionInfo[0].NumBytes = 1; - - // Seconds - TransactionInfo[1].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1); - TransactionInfo[1].Buf = &ReadBuffer[0]; - TransactionInfo[1].Flags = 0; - TransactionInfo[1].NumBytes = 1; - - // Minutes - TransactionInfo[2].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1); - TransactionInfo[2].Buf = &ReadBuffer[1]; - TransactionInfo[2].Flags = 0; - TransactionInfo[2].NumBytes = 1; - - // Hours - TransactionInfo[3].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1); - TransactionInfo[3].Buf = &ReadBuffer[2]; - TransactionInfo[3].Flags = 0; - TransactionInfo[3].NumBytes = 1; - - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 4, - MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); + NvU32 TransactionCount = 0; + ReadBuffer[0] = Addr & 0xFF; + TransactionInfo[TransactionCount].Address = MAX8907B_RTC_SLAVE_ADDR; + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = + NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Seconds / day + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Minutes / month + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[1]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Hours / YY1 + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[2]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Weekday / YY2 + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[3]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], + TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) { - *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | + *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | (ReadBuffer[2] << 8) | ReadBuffer[3]; return NV_TRUE; @@ -328,12 +353,12 @@ NvBool Max8907bRtcI2cReadTime( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c index 0c179efdf21c..50afb66beba3 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c @@ -30,151 +30,215 @@ * */ +#include <linux/time.h> +#include <linux/rtc.h> #include "max8907b.h" #include "max8907b_rtc.h" #include "max8907b_i2c.h" #include "max8907b_reg.h" -/** +/** * The Maxim 8907B does not have an RTC that simply counts * seconds from some time t0 (as defined by the OS API). * Instead, this RTC contains several BCD (Binary Coded Decimal) * registers, including: seconds, minutes, hours, days, day of * week, date, etc... These registers account for leap year and * the various days of the month as well. -* +* * Since the OS interpretation of seconds to a particular * date/time from some OS-defined t0 is unknown at this level of * the implementation, it is not possible to translate the given * seconds into these registers (at least, not without a * dependency on some OS-specific information). -* -* Therefore, this implementation contains a static variable -* (RtcDays) which is derived from the number of seconds given -* when Max8907bRtcCountWrite() is called. The seconds, minutes -* and hours are then programmed to the RTC and used to keep -* track of the current time within the day. -* -* TO DO: Increment the day whenever it rolls over (requires -* handling an interrupt at midnight each day). +* */ #define MAX8907B_SECONDS_PER_DAY (60*60*24) #define MAX8907B_SECONDS_PER_HOUR (60*60) #define MAX8907B_SECONDS_PER_MINUTE (60) +#define LINUX_RTC_BASE_YEAR 1900 + static NvBool bRtcNotInitialized = NV_TRUE; -static NvU32 RtcDays = 0; -NvBool +NvBool Max8907bRtcCountRead( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32* Count) { NvU32 data = 0; NvU32 BcdHours, BcdMinutes, BcdSeconds; NvU32 Hours, Minutes, Seconds; + NvU32 BcdDD, BcdMM, BcdYY1, BcdYY2; + NvU32 DD, MM, YY1, YY2, YYYY; + // struct rtc_time tm; - if (Max8907bRtcWasStartUpFromNoPower(hDevice) && bRtcNotInitialized) - { - Max8907bRtcCountWrite(hDevice, 0); - *Count = 0; - } - else + *Count = 0; + // Read seconds, minute, hour and weekday data from RTC registers + if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_SEC, &data)) { - if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_SEC, &data)) + NVODMPMU_PRINTF(("\n Read time data-sec=0x%x ", data)); + // Extract seconds, minute and hour data from RTC registers read + BcdHours = (data >> 8) & 0xFF; + BcdMinutes = (data >> 16) & 0xFF; + BcdSeconds = (data >> 24) & 0xFF; + + // Convert BCT time into decimal values + Hours = ((BcdHours & 0xF0)>>4)*10 + (BcdHours & 0xF); + Minutes = ((BcdMinutes & 0xF0)>>4)*10 + (BcdMinutes & 0xF); + Seconds = ((BcdSeconds & 0xF0)>>4)*10 + (BcdSeconds & 0xF); + + // Read day, month, yy1 and yy2 data from RTC registers + if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_DATE, &data)) { - - BcdHours = (data >> 8) & 0xFF; - BcdMinutes = (data >> 16) & 0xFF; - BcdSeconds = (data >> 24) & 0xFF; - - Hours = ((BcdHours & 0xF0)>>4)*10 + (BcdHours & 0xF); - Minutes = ((BcdMinutes & 0xF0)>>4)*10 + (BcdMinutes & 0xF); - Seconds = ((BcdSeconds & 0xF0)>>4)*10 + (BcdSeconds & 0xF); - - *Count = (Hours * MAX8907B_SECONDS_PER_HOUR) + - (Minutes * MAX8907B_SECONDS_PER_MINUTE) + Seconds; + NVODMPMU_PRINTF(("\n Read time data-year=0x%x ", data)); + // Extract day, month, yy1 and yy2 data from RTC registers read + BcdYY2 = (data & 0xFF); + BcdYY1 = (data >> 8) & 0xFF; + BcdMM = (data >> 16) & 0xFF; + BcdDD = (data >> 24) & 0xFF; + // convert bct day/month/year data to decimal values + YY2 = ((BcdYY2 & 0xF0)>>4)*10 + (BcdYY2 & 0xF); + YY1 = ((BcdYY1 & 0xF0)>>4)*10 + (BcdYY1 & 0xF); + YYYY = (YY2 * 100 + YY1) & 0xFFFF; + MM = ((BcdMM & 0xF0)>>4)*10 + (BcdMM & 0xF); + DD = ((BcdDD & 0xF0)>>4)*10 + (BcdDD & 0xF); + // get seconds since reference time value given + // year, month, day, hour, minutes and seconds + // NOTE: Using linux specific API mktime for conversion + *Count = mktime(YYYY, (MM + 1), DD, Hours, Minutes, Seconds); + NVODMPMU_PRINTF(("\n Rtc read count=0x%x ", *Count)); + NVODMPMU_PRINTF(("\n mktime: YYYY=%d MM=%d DD=%d Hr=%d Min=%d " + "Sec=%d, *Count=0x%x ", YYYY, (MM + 1), DD, Hours, Minutes, + Seconds, *Count)); +#if NV_DEBUG + // Call to verify that reverse conversion of seconds matches date + rtc_time_to_tm(*Count, &tm); + // Check if Local_rtc_time_to_tm can return values sent to mktime + NVODMPMU_PRINTF(("\n rtc_time_to_tm: YYYY=%d MM=%d DD=%d Hr=%d " + "Min=%d Sec=%d, *Count=0x%x ", (tm.tm_year + + LINUX_RTC_BASE_YEAR), tm.tm_mon, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, *Count)); +#endif } else { - NvOdmOsDebugPrintf("Max8907bRtcCountRead() error. "); + NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. ")); return NV_FALSE; } } + else + { + NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. ")); + return NV_FALSE; + } + NVODMPMU_PRINTF(("\n *Count=0x%x ", *Count)); return NV_TRUE; } -NvBool +NvBool Max8907bRtcAlarmCountRead( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32* Count) { return NV_FALSE; } -NvBool +NvBool Max8907bRtcCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { - NvU32 Hours, Minutes, Seconds; NvU32 BcdHours, BcdMinutes, BcdSeconds; NvU32 data = 0; - - BcdHours = BcdMinutes = BcdSeconds = 0; - - RtcDays = Count / MAX8907B_SECONDS_PER_DAY; - - Hours = (Count % MAX8907B_SECONDS_PER_DAY) / MAX8907B_SECONDS_PER_HOUR; - Minutes = ((Count % MAX8907B_SECONDS_PER_DAY) % MAX8907B_SECONDS_PER_HOUR) / MAX8907B_SECONDS_PER_MINUTE; - Seconds = Count % MAX8907B_SECONDS_PER_MINUTE; - - BcdHours = (( Hours/10) << 4) | ( Hours%10); - BcdMinutes = ((Minutes/10) << 4) | (Minutes%10); - BcdSeconds = ((Seconds/10) << 4) | (Seconds%10); + NvU8 BcdDD, BcdMM, BcdYY1, BcdYY2; + NvU16 YYYY; + struct rtc_time tm; + NvU32 data1; + + NVODMPMU_PRINTF(("\n Rtc write count=0x%x ", Count)); + // convert seconds since reference time into date + // NOTE: using linux specific convert function rtc_time_to_tm + rtc_time_to_tm(Count, &tm); + NVODMPMU_PRINTF(("\n rtc_time_to_tm: YYYY=%d MM=%d DD=%d Hr=%d Min=%d " + "Sec=%d, *Count=0x%x ", (tm.tm_year + LINUX_RTC_BASE_YEAR), + (tm.tm_mon + 1), tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, Count)); + + // Convert time to bcd format + BcdHours = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10); + BcdMinutes = ((tm.tm_min/10) << 4) | (tm.tm_min%10); + BcdSeconds = ((tm.tm_sec/10) << 4) | (tm.tm_sec%10); data = (BcdSeconds << 24) | (BcdMinutes << 16) | (BcdHours << 8); + // write time - seconds, minutes and hours in a day to RTC registers if (Max8907bRtcI2cWriteTime(hDevice, MAX8907B_RTC_SEC, data)) { - bRtcNotInitialized = NV_FALSE; - return NV_TRUE; + // set the day, month, year + // Assuming we get the days since 1 Jan 1970 + + // convert date to bct format + BcdDD = (((NvU8)tm.tm_mday / 10) << 4) | ((NvU8)tm.tm_mday % 10); + BcdMM = (((NvU8)tm.tm_mon / 10) << 4) | ((NvU8)tm.tm_mon % 10); + YYYY = (NvU16)tm.tm_year + LINUX_RTC_BASE_YEAR; + BcdYY1 = (((NvU8)(YYYY % 100) / 10) << 4) | ((NvU8)(YYYY % 100) % 10); + BcdYY2 = (((NvU8)(YYYY / 100) / 10) << 4) | ((NvU8)(YYYY / 100) % 10); + data = (NvU32)((BcdDD << 24) | (BcdMM << 16) | (BcdYY1 << 8) | BcdYY2); + // write date - day, month, and year to RTC registers + if (!(Max8907bRtcI2cWriteTime(hDevice, MAX8907B_RTC_DATE, data))) + { + NVODMPMU_PRINTF(("\n Max8907bRtcCountWrite() error. ")); + return NV_FALSE; + } +#if NV_DEBUG + // verify that read back values from RTC matches written values + if (!(Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_DATE, &data1))) + { + NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. ")); + return NV_FALSE; + } + if (data1 == data) + { + NVODMPMU_PRINTF(("\n Write read Success. ")); + return NV_TRUE; + } + else + { + // return error when read data does not match written data + NVODMPMU_PRINTF(("\n Error: write data=0x%x, rd data=0x%x. ", data, data1)); + return NV_FALSE; + } +#endif } else { - NvOdmOsDebugPrintf("Max8907bRtcCountWrite() error. "); + NVODMPMU_PRINTF(("\n Max8907bRtcCountWrite() error. ")); return NV_FALSE; } } -NvBool +NvBool Max8907bRtcAlarmCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { return NV_FALSE; } -NvBool +NvBool Max8907bRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice) { return NV_FALSE; } -NvBool +NvBool Max8907bRtcAlarmIntEnable( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvBool Enable) { return NV_FALSE; } -NvBool -Max8907bRtcWasStartUpFromNoPower(NvOdmPmuDeviceHandle hDevice) -{ - return NV_TRUE; -} - NvBool Max8907bIsRtcInitialized(NvOdmPmuDeviceHandle hDevice) { diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c index d897eb9f4ee3..29f52e2d7ae0 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c @@ -30,10 +30,20 @@ * */ +#include <linux/time.h> #include "nvodm_pmu_tps6586x_rtc.h" #include "nvodm_pmu_tps6586x_i2c.h" #include "tps6586x_reg.h" +// macro SHIFT_TO_2009 if 1, uses 2009 as reference year instead of 1970 +// This is because RTC in PMU TPS6586x can store duration of 34 years, +// else we cannot retain date beyond 2004 +#define SHIFT_TO_2009 1 +#if SHIFT_TO_2009 +static unsigned long epoch = 2009; +static unsigned long epoch_sec = 0; +#endif + static NvBool bRtcNotInitialized = NV_TRUE; /* Read RTC count register */ @@ -43,12 +53,12 @@ Tps6586xRtcCountRead( NvU32* Count) { NvU32 ReadBuffer[2]; - + // 1) The I2C address pointer must not be left pointing in the range 0xC6 to 0xCA // 2) The maximum time for the address pointer to be in this range is 1ms // 3) Always read RTC_ALARM2 in the following order to prevent the address pointer - // from stopping at 0xC6: RTC_ALARM2_LO, then RTC_ALARM2_HI - + // from stopping at 0xC6: RTC_ALARM2_LO, then RTC_ALARM2_HI + if (Tps6586xRtcWasStartUpFromNoPower(hDevice) && bRtcNotInitialized) { Tps6586xRtcCountWrite(hDevice, 0); @@ -59,55 +69,76 @@ Tps6586xRtcCountRead( // The unit of the RTC count is second!!! 1024 tick = 1s. // Read all 40 bit and right move 10 = Read the hightest 32bit and right move 2 Tps6586xI2cRead32(hDevice, TPS6586x_RC6_RTC_COUNT4, &ReadBuffer[0]); - + Tps6586xI2cRead8(hDevice, TPS6586x_RCA_RTC_COUNT0, &ReadBuffer[1]); - + Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer[1]); - + // return second *Count = ReadBuffer[0]>>2; } - +#if SHIFT_TO_2009 + // calculate epoch_sec once + if (!epoch_sec) + epoch_sec = mktime(epoch,1,1,0,0,0); + *Count += epoch_sec; +#endif + return NV_TRUE; } /* Write RTC count register */ -NvBool +NvBool Tps6586xRtcCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { NvU32 ReadBuffer = 0; - +#if SHIFT_TO_2009 + // calculate epoch_sec once + if (!epoch_sec) + epoch_sec = mktime(epoch,1,1,0,0,0); + if (Count < (NvU32)epoch_sec) + { + // prevent setting date earlier than 'epoch' + pr_warning("\n Date being set cannot be earlier than least year=%d. " + "Setting as least year. ", (int)epoch); + // base year seconds count is 0 + Count = 0; + } + else + Count -= (NvU32)epoch_sec; +#endif + // To enable incrementing of the RTC_COUNT[39:0] from an initial value set by the host, - // the RTC_ENABLE bit should be written to 1 only after the RTC_OUT voltage reaches + // the RTC_ENABLE bit should be written to 1 only after the RTC_OUT voltage reaches // the operating range - + // Clear RTC_ENABLE before writing RTC_COUNT Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer); ReadBuffer = ReadBuffer & 0xDF; Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer); - + Tps6586xI2cWrite32(hDevice, TPS6586x_RC6_RTC_COUNT4, (Count<<2)); - Tps6586xI2cWrite8(hDevice, TPS6586x_RCA_RTC_COUNT0, 0); - + Tps6586xI2cWrite8(hDevice, TPS6586x_RCA_RTC_COUNT0, 0); + // Set RTC_ENABLE after writing RTC_COUNT Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer); ReadBuffer = ReadBuffer | 0x20; Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer); - + if (bRtcNotInitialized) bRtcNotInitialized = NV_FALSE; - + return NV_TRUE; } /* Read RTC alarm count register */ -NvBool +NvBool Tps6586xRtcAlarmCountRead( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32* Count) { return NV_FALSE; @@ -115,9 +146,9 @@ Tps6586xRtcAlarmCountRead( /* Write RTC alarm count register */ -NvBool +NvBool Tps6586xRtcAlarmCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { return NV_FALSE; @@ -125,7 +156,7 @@ Tps6586xRtcAlarmCountWrite( /* Reads RTC alarm interrupt mask status */ -NvBool +NvBool Tps6586xRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice) { return NV_FALSE; @@ -133,9 +164,9 @@ Tps6586xRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice) /* Enables / Disables the RTC alarm interrupt */ -NvBool +NvBool Tps6586xRtcAlarmIntEnable( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvBool Enable) { return NV_FALSE; @@ -143,7 +174,7 @@ Tps6586xRtcAlarmIntEnable( /* Checks if boot was from nopower / powered state */ -NvBool +NvBool Tps6586xRtcWasStartUpFromNoPower(NvOdmPmuDeviceHandle hDevice) { NvU32 Data = 0; diff --git a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c index 7aded70cbb6c..ed5e81da1d38 100644 --- a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c +++ b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c @@ -1187,7 +1187,7 @@ NvOdmQueryGetUsbProperty(NvOdmIoModule OdmIoModule, (NvOdmUsbChargerType_SE0 | NvOdmUsbChargerType_SE1 | NvOdmUsbChargerType_SK), 20, NV_TRUE, - NvOdmUsbModeType_Device, + NvOdmUsbModeType_OTG, NvOdmUsbIdPinType_CableId, NvOdmUsbConnectorsMuxType_None, NV_FALSE diff --git a/arch/arm/mach-tegra/pci-enum.c b/arch/arm/mach-tegra/pci-enum.c index 4f8c614ff8fc..1bcf659fe696 100644 --- a/arch/arm/mach-tegra/pci-enum.c +++ b/arch/arm/mach-tegra/pci-enum.c @@ -494,7 +494,7 @@ static void pci_tegra_setup_pci_device(struct pci_tegra_device *dev) } dev->res[bar_index].flags = IORESOURCE_MEM; - dev->res[bar_index].start = 0; + dev->res[bar_index].start = addr; dev->res[bar_index].end = dev->res[bar_index].start + size - 1; @@ -522,7 +522,7 @@ static void pci_tegra_setup_pci_device(struct pci_tegra_device *dev) /* Handle 64 bit addresses by forcing to 32 bit addresses */ if ((flags == 0x0c) || (flags==0x04)) { bar_index++; - BUG_ON(bar_index < 6); + BUG_ON(bar_index > PCI_STD_RESOURCE_END); pci_conf_write32(dev->bus, dev->devfn, bar_index * 4 + PCI_BASE_ADDRESS_0, 0); } diff --git a/arch/arm/mach-tegra/pci.c b/arch/arm/mach-tegra/pci.c index c4ced311e223..5118692b1b79 100644 --- a/arch/arm/mach-tegra/pci.c +++ b/arch/arm/mach-tegra/pci.c @@ -33,6 +33,7 @@ #include <mach/pci.h> #include <mach/nvrm_linux.h> +#include <mach/board.h> #include "nvrm_pmu.h" #include "nvodm_query_discovery.h" @@ -362,7 +363,7 @@ static int __init pci_tegra_setup(int nr, struct pci_sys_data *data) 0, NULL); NvRmPowerModuleClockControl(s_hRmGlobal, NvRmPrivModuleID_Pcie, pci_tegra_powerid, NV_FALSE); - pci_tegra_power(0); + tegra_set_voltage(NV_VDD_PEX_CLK_ODM_ID, 0); return 0; } pci_tegra_device_attached = true; @@ -402,12 +403,21 @@ static struct pci_bus __init *pci_tegra_scan_bus(int nr, return NULL; } +int pci_tegra_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int ret = 0; + pci_tegra_read_conf(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, + sizeof(int), &ret); + return (ret & 0x000000ff); +} + static struct hw_pci pci_tegra_data __initdata = { .nr_controllers = 2, .preinit = pci_tegra_preinit, .setup = pci_tegra_setup, .scan = pci_tegra_scan_bus, .swizzle = pci_std_swizzle, + .map_irq = pci_tegra_map_irq, }; late_initcall(pcie_tegra_init); diff --git a/arch/arm/mach-tegra/power-lp.S b/arch/arm/mach-tegra/power-lp.S index 48c09640fd30..acc7645e34c1 100644 --- a/arch/arm/mach-tegra/power-lp.S +++ b/arch/arm/mach-tegra/power-lp.S @@ -66,7 +66,9 @@ wait_for_other_cores: beq finish_power_state //Save the local timers + stmfd sp!, {r1} bl save_local_timers + ldmfd sp!, {r1} //Ok we can save state for core0 now save_arm_state: diff --git a/arch/arm/mach-tegra/tegra_rfkill_odm.c b/arch/arm/mach-tegra/tegra_rfkill_odm.c index ff4ebfb4361d..0ef0f060b9b0 100644 --- a/arch/arm/mach-tegra/tegra_rfkill_odm.c +++ b/arch/arm/mach-tegra/tegra_rfkill_odm.c @@ -34,7 +34,7 @@ #define DRIVER_DESC "Nvidia Tegra rfkill" static NvRmGpioHandle hGpio = NULL; -static NvRmGpioPinHandle hBlueToothPowerPin = 0; +static NvRmGpioPinHandle hBlueToothResetPin = 0; static NvU32 blueToothPowerRailId = 0xff; static struct rfkill *bt = NULL; @@ -47,7 +47,7 @@ static int bluetooth_set_power(void *data, enum rfkill_state state) NvU32 settletime = 0; NvU32 GpioLevel; - if (blueToothPowerRailId == 0xff || !hBlueToothPowerPin || !hGpio) + if (blueToothPowerRailId == 0xff || !hBlueToothResetPin || !hGpio) return -ENXIO; hPmu = NvOdmServicesPmuOpen(); @@ -58,21 +58,24 @@ static int bluetooth_set_power(void *data, enum rfkill_state state) case RFKILL_STATE_UNBLOCKED: NvOdmServicesPmuGetCapabilities(hPmu, blueToothPowerRailId, &vddrailcap); - NvOdmServicesPmuSetVoltage(hPmu, blueToothPowerRailId, + NvOdmServicesPmuSetVoltage(hPmu, blueToothPowerRailId, vddrailcap.requestMilliVolts, &settletime); if (settletime) NvOdmOsWaitUS(settletime); - /* Enable power */ + /* Pulse a reset */ GpioLevel = 0; - NvRmGpioWritePins(hGpio, &hBlueToothPowerPin, &GpioLevel, 1); + NvRmGpioWritePins(hGpio, &hBlueToothResetPin, &GpioLevel, 1); /* Configure as output */ - NvRmGpioConfigPins(hGpio, &hBlueToothPowerPin, 1, + NvRmGpioConfigPins(hGpio, &hBlueToothResetPin, 1, NvRmGpioPinMode_Output); - + + /* Give 5 milli seconds for the reset pulse */ + NvOdmOsSleepMS(5); + GpioLevel = 1; - NvRmGpioWritePins(hGpio, &hBlueToothPowerPin, &GpioLevel, 1); + NvRmGpioWritePins(hGpio, &hBlueToothResetPin, &GpioLevel, 1); printk(KERN_INFO "Bluetooth power ON\n"); break; @@ -80,13 +83,13 @@ static int bluetooth_set_power(void *data, enum rfkill_state state) case RFKILL_STATE_SOFT_BLOCKED: /* Disable power */ GpioLevel = 0; - NvRmGpioWritePins(hGpio, &hBlueToothPowerPin, &GpioLevel, 1); + NvRmGpioWritePins(hGpio, &hBlueToothResetPin, &GpioLevel, 1); /* Configure as output */ - NvRmGpioConfigPins(hGpio, &hBlueToothPowerPin, 1, + NvRmGpioConfigPins(hGpio, &hBlueToothResetPin, 1, NvRmGpioPinMode_Output); - NvOdmServicesPmuSetVoltage( hPmu, blueToothPowerRailId, + NvOdmServicesPmuSetVoltage( hPmu, blueToothPowerRailId, NVODM_VOLTAGE_OFF, &settletime); if (settletime) NvOdmOsWaitUS(settletime); @@ -112,7 +115,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev) NvU64 bluetooth = NV_ODM_GUID('b','l','u','t','o','o','t','h'); /* conn will be null if bluetooth is not present. */ - conn = + conn = NvOdmPeripheralGetGuid(bluetooth); if (!conn) return -ENXIO; @@ -121,7 +124,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev) if (conn->AddressList[i].Interface == NvOdmIoModule_Gpio) { port = conn->AddressList[i].Instance; pin = conn->AddressList[i].Address; - } + } if (conn->AddressList[i].Interface == NvOdmIoModule_Vdd) { blueToothPowerRailId = conn->AddressList[i].Address; } @@ -137,7 +140,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev) printk(KERN_ERR "NvRmGpioOpen failed\n"); return -ENXIO; } - err = NvRmGpioAcquirePinHandle(hGpio, port, pin, &hBlueToothPowerPin); + err = NvRmGpioAcquirePinHandle(hGpio, port, pin, &hBlueToothResetPin); if (err) { printk(KERN_ERR "NvRmGpioAcquirePinHandle failed\n"); NvRmGpioClose(hGpio); @@ -146,7 +149,7 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev) rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED); bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED); - + bt = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH); if (!bt) { rc = -ENOMEM; @@ -163,12 +166,12 @@ static int __init tegra_rfkill_probe(struct platform_device *pdev) rc = rfkill_register(bt); if (rc) goto fail; - + return rc; fail: - if (hBlueToothPowerPin) - NvRmGpioReleasePinHandles(hGpio, &hBlueToothPowerPin, 1); + if (hBlueToothResetPin) + NvRmGpioReleasePinHandles(hGpio, &hBlueToothResetPin, 1); if (hGpio) NvRmGpioClose(hGpio); @@ -183,8 +186,8 @@ static int __init tegra_rfkill_remove(struct platform_device *pdev) rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED); bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED); - if (hBlueToothPowerPin) - NvRmGpioReleasePinHandles(hGpio, &hBlueToothPowerPin, 1); + if (hBlueToothResetPin) + NvRmGpioReleasePinHandles(hGpio, &hBlueToothResetPin, 1); if (hGpio) NvRmGpioClose(hGpio); @@ -214,4 +217,3 @@ static int __init tegra_rfkill_init(void) module_init(tegra_rfkill_init); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - |