162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copied from <file:arch/powerpc/kernel/misc_32.S>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This file contains miscellaneous low-level functions.
662306a36Sopenharmony_ci *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
962306a36Sopenharmony_ci * and Paul Mackerras.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * kexec bits:
1262306a36Sopenharmony_ci * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
1362306a36Sopenharmony_ci * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci#include "ppc_asm.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define SPRN_PVR        0x11F   /* Processor Version Register */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	.text
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* udelay needs to know the period of the
2262306a36Sopenharmony_ci * timebase in nanoseconds.  This used to be hardcoded to be 60ns
2362306a36Sopenharmony_ci * (period of 66MHz/4).  Now a variable is used that is initialized to
2462306a36Sopenharmony_ci * 60 for backward compatibility, but it can be overridden as necessary
2562306a36Sopenharmony_ci * with code something like this:
2662306a36Sopenharmony_ci *    extern unsigned long timebase_period_ns;
2762306a36Sopenharmony_ci *    timebase_period_ns = 1000000000 / bd->bi_tbfreq;
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci	.data
3062306a36Sopenharmony_ci	.globl timebase_period_ns
3162306a36Sopenharmony_citimebase_period_ns:
3262306a36Sopenharmony_ci	.long	60
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	.text
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Delay for a number of microseconds
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci	.globl	udelay
3962306a36Sopenharmony_ciudelay:
4062306a36Sopenharmony_ci	mulli	r4,r3,1000	/* nanoseconds */
4162306a36Sopenharmony_ci	/*  Change r4 to be the number of ticks using:
4262306a36Sopenharmony_ci	 *	(nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
4362306a36Sopenharmony_ci	 *  timebase_period_ns defaults to 60 (16.6MHz) */
4462306a36Sopenharmony_ci	mflr	r5
4562306a36Sopenharmony_ci	bcl	20,31,0f
4662306a36Sopenharmony_ci0:	mflr	r6
4762306a36Sopenharmony_ci	mtlr	r5
4862306a36Sopenharmony_ci	addis	r5,r6,(timebase_period_ns-0b)@ha
4962306a36Sopenharmony_ci	lwz	r5,(timebase_period_ns-0b)@l(r5)
5062306a36Sopenharmony_ci	add	r4,r4,r5
5162306a36Sopenharmony_ci	addi	r4,r4,-1
5262306a36Sopenharmony_ci	divw	r4,r4,r5	/* BUS ticks */
5362306a36Sopenharmony_ci1:	MFTBU(r5)
5462306a36Sopenharmony_ci	MFTBL(r6)
5562306a36Sopenharmony_ci	MFTBU(r7)
5662306a36Sopenharmony_ci	cmpw	0,r5,r7
5762306a36Sopenharmony_ci	bne	1b		/* Get [synced] base time */
5862306a36Sopenharmony_ci	addc	r9,r6,r4	/* Compute end time */
5962306a36Sopenharmony_ci	addze	r8,r5
6062306a36Sopenharmony_ci2:	MFTBU(r5)
6162306a36Sopenharmony_ci	cmpw	0,r5,r8
6262306a36Sopenharmony_ci	blt	2b
6362306a36Sopenharmony_ci	bgt	3f
6462306a36Sopenharmony_ci	MFTBL(r6)
6562306a36Sopenharmony_ci	cmpw	0,r6,r9
6662306a36Sopenharmony_ci	blt	2b
6762306a36Sopenharmony_ci3:	blr
68