diff options
| -rw-r--r-- | drivers/memory/emif.c | 211 |
1 files changed, 209 insertions, 2 deletions
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index bd116eb8c738..a8dcf3515573 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c | |||
| @@ -545,6 +545,42 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) | |||
| 545 | } | 545 | } |
| 546 | 546 | ||
| 547 | /* | 547 | /* |
| 548 | * Get the temperature level of the EMIF instance: | ||
| 549 | * Reads the MR4 register of attached SDRAM parts to find out the temperature | ||
| 550 | * level. If there are two parts attached(one on each CS), then the temperature | ||
| 551 | * level for the EMIF instance is the higher of the two temperatures. | ||
| 552 | */ | ||
| 553 | static void get_temperature_level(struct emif_data *emif) | ||
| 554 | { | ||
| 555 | u32 temp, temperature_level; | ||
| 556 | void __iomem *base; | ||
| 557 | |||
| 558 | base = emif->base; | ||
| 559 | |||
| 560 | /* Read mode register 4 */ | ||
| 561 | writel(DDR_MR4, base + EMIF_LPDDR2_MODE_REG_CONFIG); | ||
| 562 | temperature_level = readl(base + EMIF_LPDDR2_MODE_REG_DATA); | ||
| 563 | temperature_level = (temperature_level & MR4_SDRAM_REF_RATE_MASK) >> | ||
| 564 | MR4_SDRAM_REF_RATE_SHIFT; | ||
| 565 | |||
| 566 | if (emif->plat_data->device_info->cs1_used) { | ||
| 567 | writel(DDR_MR4 | CS_MASK, base + EMIF_LPDDR2_MODE_REG_CONFIG); | ||
| 568 | temp = readl(base + EMIF_LPDDR2_MODE_REG_DATA); | ||
| 569 | temp = (temp & MR4_SDRAM_REF_RATE_MASK) | ||
| 570 | >> MR4_SDRAM_REF_RATE_SHIFT; | ||
| 571 | temperature_level = max(temp, temperature_level); | ||
| 572 | } | ||
| 573 | |||
| 574 | /* treat everything less than nominal(3) in MR4 as nominal */ | ||
| 575 | if (unlikely(temperature_level < SDRAM_TEMP_NOMINAL)) | ||
| 576 | temperature_level = SDRAM_TEMP_NOMINAL; | ||
| 577 | |||
| 578 | /* if we get reserved value in MR4 persist with the existing value */ | ||
| 579 | if (likely(temperature_level != SDRAM_TEMP_RESERVED_4)) | ||
| 580 | emif->temperature_level = temperature_level; | ||
| 581 | } | ||
| 582 | |||
| 583 | /* | ||
| 548 | * Program EMIF shadow registers that are not dependent on temperature | 584 | * Program EMIF shadow registers that are not dependent on temperature |
| 549 | * or voltage | 585 | * or voltage |
| 550 | */ | 586 | */ |
| @@ -627,6 +663,158 @@ out: | |||
| 627 | writel(ref_ctrl, base + EMIF_SDRAM_REFRESH_CTRL_SHDW); | 663 | writel(ref_ctrl, base + EMIF_SDRAM_REFRESH_CTRL_SHDW); |
| 628 | } | 664 | } |
| 629 | 665 | ||
| 666 | static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) | ||
| 667 | { | ||
| 668 | u32 old_temp_level; | ||
| 669 | irqreturn_t ret = IRQ_HANDLED; | ||
| 670 | |||
| 671 | spin_lock_irqsave(&emif_lock, irq_state); | ||
| 672 | old_temp_level = emif->temperature_level; | ||
| 673 | get_temperature_level(emif); | ||
| 674 | |||
| 675 | if (unlikely(emif->temperature_level == old_temp_level)) { | ||
| 676 | goto out; | ||
| 677 | } else if (!emif->curr_regs) { | ||
| 678 | dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); | ||
| 679 | goto out; | ||
| 680 | } | ||
| 681 | |||
| 682 | if (emif->temperature_level < old_temp_level || | ||
| 683 | emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { | ||
| 684 | /* | ||
| 685 | * Temperature coming down - defer handling to thread OR | ||
| 686 | * Temperature far too high - do kernel_power_off() from | ||
| 687 | * thread context | ||
| 688 | */ | ||
| 689 | ret = IRQ_WAKE_THREAD; | ||
| 690 | } else { | ||
| 691 | /* Temperature is going up - handle immediately */ | ||
| 692 | setup_temperature_sensitive_regs(emif, emif->curr_regs); | ||
| 693 | do_freq_update(); | ||
| 694 | } | ||
| 695 | |||
| 696 | out: | ||
| 697 | spin_unlock_irqrestore(&emif_lock, irq_state); | ||
| 698 | return ret; | ||
| 699 | } | ||
| 700 | |||
| 701 | static irqreturn_t emif_interrupt_handler(int irq, void *dev_id) | ||
| 702 | { | ||
| 703 | u32 interrupts; | ||
| 704 | struct emif_data *emif = dev_id; | ||
| 705 | void __iomem *base = emif->base; | ||
| 706 | struct device *dev = emif->dev; | ||
| 707 | irqreturn_t ret = IRQ_HANDLED; | ||
| 708 | |||
| 709 | /* Save the status and clear it */ | ||
| 710 | interrupts = readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS); | ||
| 711 | writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS); | ||
| 712 | |||
| 713 | /* | ||
| 714 | * Handle temperature alert | ||
| 715 | * Temperature alert should be same for all ports | ||
| 716 | * So, it's enough to process it only for one of the ports | ||
| 717 | */ | ||
| 718 | if (interrupts & TA_SYS_MASK) | ||
| 719 | ret = handle_temp_alert(base, emif); | ||
| 720 | |||
| 721 | if (interrupts & ERR_SYS_MASK) | ||
| 722 | dev_err(dev, "Access error from SYS port - %x\n", interrupts); | ||
| 723 | |||
| 724 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) { | ||
| 725 | /* Save the status and clear it */ | ||
| 726 | interrupts = readl(base + EMIF_LL_OCP_INTERRUPT_STATUS); | ||
| 727 | writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_STATUS); | ||
| 728 | |||
| 729 | if (interrupts & ERR_LL_MASK) | ||
| 730 | dev_err(dev, "Access error from LL port - %x\n", | ||
| 731 | interrupts); | ||
| 732 | } | ||
| 733 | |||
| 734 | return ret; | ||
| 735 | } | ||
| 736 | |||
| 737 | static irqreturn_t emif_threaded_isr(int irq, void *dev_id) | ||
| 738 | { | ||
| 739 | struct emif_data *emif = dev_id; | ||
| 740 | |||
| 741 | if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { | ||
| 742 | dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); | ||
| 743 | kernel_power_off(); | ||
| 744 | return IRQ_HANDLED; | ||
| 745 | } | ||
| 746 | |||
| 747 | spin_lock_irqsave(&emif_lock, irq_state); | ||
| 748 | |||
| 749 | if (emif->curr_regs) { | ||
| 750 | setup_temperature_sensitive_regs(emif, emif->curr_regs); | ||
| 751 | do_freq_update(); | ||
| 752 | } else { | ||
| 753 | dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); | ||
| 754 | } | ||
| 755 | |||
| 756 | spin_unlock_irqrestore(&emif_lock, irq_state); | ||
| 757 | |||
| 758 | return IRQ_HANDLED; | ||
| 759 | } | ||
| 760 | |||
| 761 | static void clear_all_interrupts(struct emif_data *emif) | ||
| 762 | { | ||
| 763 | void __iomem *base = emif->base; | ||
| 764 | |||
| 765 | writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS), | ||
| 766 | base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS); | ||
| 767 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) | ||
| 768 | writel(readl(base + EMIF_LL_OCP_INTERRUPT_STATUS), | ||
| 769 | base + EMIF_LL_OCP_INTERRUPT_STATUS); | ||
| 770 | } | ||
| 771 | |||
| 772 | static void disable_and_clear_all_interrupts(struct emif_data *emif) | ||
| 773 | { | ||
| 774 | void __iomem *base = emif->base; | ||
| 775 | |||
| 776 | /* Disable all interrupts */ | ||
| 777 | writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET), | ||
| 778 | base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR); | ||
| 779 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) | ||
| 780 | writel(readl(base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET), | ||
| 781 | base + EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR); | ||
| 782 | |||
| 783 | /* Clear all interrupts */ | ||
| 784 | clear_all_interrupts(emif); | ||
| 785 | } | ||
| 786 | |||
| 787 | static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq) | ||
| 788 | { | ||
| 789 | u32 interrupts, type; | ||
| 790 | void __iomem *base = emif->base; | ||
| 791 | |||
| 792 | type = emif->plat_data->device_info->type; | ||
| 793 | |||
| 794 | clear_all_interrupts(emif); | ||
| 795 | |||
| 796 | /* Enable interrupts for SYS interface */ | ||
| 797 | interrupts = EN_ERR_SYS_MASK; | ||
| 798 | if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) | ||
| 799 | interrupts |= EN_TA_SYS_MASK; | ||
| 800 | writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET); | ||
| 801 | |||
| 802 | /* Enable interrupts for LL interface */ | ||
| 803 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) { | ||
| 804 | /* TA need not be enabled for LL */ | ||
| 805 | interrupts = EN_ERR_LL_MASK; | ||
| 806 | writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET); | ||
| 807 | } | ||
| 808 | |||
| 809 | /* setup IRQ handlers */ | ||
| 810 | return devm_request_threaded_irq(emif->dev, irq, | ||
| 811 | emif_interrupt_handler, | ||
| 812 | emif_threaded_isr, | ||
| 813 | 0, dev_name(emif->dev), | ||
| 814 | emif); | ||
| 815 | |||
| 816 | } | ||
| 817 | |||
| 630 | static void get_default_timings(struct emif_data *emif) | 818 | static void get_default_timings(struct emif_data *emif) |
