clock.c 3.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2 3 4 5 6 7
/*
 * Copyright (C) 2015 Atmel Corporation
 *		      Wenyou Yang <wenyou.yang@atmel.com>
 */

#include <common.h>
8 9
#include <dm.h>
#include <wdt.h>
10 11 12
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pmc.h>
13
#include <asm/arch/at91_wdt.h>
14

15 16
#define EN_UPLL_TIMEOUT		500

17 18
static struct udevice *watchdog_dev __attribute__((section(".data"))) = NULL;

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
void at91_periph_clk_enable(int id)
{
	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;

#ifdef CPU_HAS_PCR
	u32 regval;
	u32 div_value;

	if (id > AT91_PMC_PCR_PID_MASK)
		return;

	writel(id, &pmc->pcr);

	div_value = readl(&pmc->pcr) & AT91_PMC_PCR_DIV;

	regval = AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD_WRITE | id | div_value;

	writel(regval, &pmc->pcr);
#else
	writel(0x01 << id, &pmc->pcer);
#endif
}

void at91_periph_clk_disable(int id)
{
	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;

#ifdef CPU_HAS_PCR
	u32 regval;

	if (id > AT91_PMC_PCR_PID_MASK)
		return;

	regval = AT91_PMC_PCR_CMD_WRITE | id;

	writel(regval, &pmc->pcr);
#else
	writel(0x01 << id, &pmc->pcdr);
#endif
}

void at91_system_clk_enable(int sys_clk)
{
	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;

	writel(sys_clk, &pmc->scer);
}

void at91_system_clk_disable(int sys_clk)
{
	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;

	writel(sys_clk, &pmc->scdr);
}
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

int at91_upll_clk_enable(void)
{
	struct at91_pmc *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
	ulong start_time, tmp_time;

	if ((readl(&pmc->uckr) & AT91_PMC_UPLLEN) == AT91_PMC_UPLLEN)
		return 0;

	start_time = get_timer(0);
	writel(AT91_PMC_UPLLEN | AT91_PMC_BIASEN, &pmc->uckr);
	while ((readl(&pmc->sr) & AT91_PMC_LOCKU) != AT91_PMC_LOCKU) {
		tmp_time = get_timer(0);
		if ((tmp_time - start_time) > EN_UPLL_TIMEOUT) {
			printf("ERROR: failed to enable UPLL\n");
			return -1;
		}
	}

	return 0;
}

int at91_upll_clk_disable(void)
{
	struct at91_pmc *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
	ulong start_time, tmp_time;

	start_time = get_timer(0);
	writel(readl(&pmc->uckr) & ~AT91_PMC_UPLLEN, &pmc->uckr);
	while ((readl(&pmc->sr) & AT91_PMC_LOCKU) == AT91_PMC_LOCKU) {
		tmp_time = get_timer(0);
		if ((tmp_time - start_time) > EN_UPLL_TIMEOUT) {
			printf("ERROR: failed to stop UPLL\n");
			return -1;
		}
	}

	return 0;
}

void at91_usb_clk_init(u32 value)
{
	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;

	writel(value, &pmc->usb);
}
119 120 121 122 123 124 125

void at91_pllicpr_init(u32 icpr)
{
	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;

	writel(icpr, &pmc->pllicpr);
}
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
	static ulong next_reset;
	ulong now;

	if (!watchdog_dev)
		return;

	now = get_timer(0);

	/* Do not reset the watchdog too often */
	if (now > next_reset) {
		next_reset = now + 1000;	/* reset every 1000ms */
		wdt_reset(watchdog_dev);
	}
}

int arch_early_init_r(void)
{
	struct at91_wdt_priv *priv;

	/* Init watchdog */
	if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
		debug("Watchdog: Not found by seq!\n");
		if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) {
			puts("Watchdog: Not found!\n");
			return 0;
		}
	}

	priv = dev_get_priv(watchdog_dev);
	if (!priv) {
		printf("Watchdog: priv not available!\n");
		return 0;
	}

	wdt_start(watchdog_dev, priv->timeout * 1000, 0);
	printf("Watchdog: Started\n");

	return 0;
}