Another way to achieve this is to have P1 reference P2 as project in the solution, but have P2 reference P1 just by its output DLL or EXE.
You lose some cross project / dependency checking, but it does allow you to cross reference.
I had to do this with a long-running WinForms application that was originally written in VB but moved to C# after some years. All new Windows Forms were written in C#, which couldn't be the same project as the VB forms, but some VB forms needed to call the new C# forms and vice verca.
EDIT 1
One drawback with this is that, if P2 references P1 as it's project output DLL/EXE and then, when you clean / rebuild the solution, there's an error, you are in the position where the output DLL/EXE no longer exists and can't be recreated until you resolve the error, but the solution can no longer be built as it has a missing reference. Not a good place to be, so make sure to keep a copy of your output DLL/EXE from time to time so you can get out of this if it ever happens.